/// <summary> /// Creates <see cref="SequencePointRemapper">SequencePointRemapper</see> - sequence point difference tool for /// specified method used in debug state refreshing and local variables definition. /// </summary> /// <param name="methodDef">Method to which generating takes place.</param> /// <returns>Instance of <see cref="SequencePointRemapper">SequencePointRemapper</see>.</returns> private SequencePointRemapper genSequencePointRemapper(MethodDefinition methodDefOld, MethodDefinition methodDefNew) { uint token = methodDefOld.MetadataToken.ToUInt32(); List <SequencePoint> oldSeqs = SymbolWriterClass.GetMethodSequencePoints( Manager.ResourceManager.CurrentModule.SymReader, methodDefOld.MetadataToken.ToUInt32()); List <SequencePoint> newSeqs = SymbolWriterClass.GetMethodSequencePoints( SymbolWriter.CorSymNewReader, methodDefNew.MetadataToken.ToUInt32()); SequencePointRemapper remapper = new SequencePointRemapper(oldSeqs, newSeqs, Manager.ActualEditEvent.sourceTextChanges[token]); SequencePointRemappers.Add(token, remapper); return(remapper); }
/// <summary> /// Change IL code and metadata for property. /// </summary> /// <param name="property">Interaface with info abour property.</param> /// <param name="isGetter">Determines whether it is getter method for property.</param> public void ChangeProperty(IProperty property, bool isGetter) { // Method RVA is offset to start of byte buffer uint RVA = (uint)dIL.Count + 4; PropertyDefinition targtProp, targtPropOld; MethodDefinition targtMet, targtMetOld; // Find appropriete new version of method in new assembly. targtProp = Manager.MetadataManager.FindProperty(Manager.ResourceManager.NewAssembly, Manager.ResourceManager.NewAssemblyName, property); if (targtProp == null) { new TranslatingException("Property " + property.ToString() + " could not be found in emitted module"); } // Find appropriete original version of method in running assembly. targtPropOld = Manager.MetadataManager.FindProperty(Manager.ResourceManager.OldAssembly, Manager.ResourceManager.CurrentModule.Name, property); if (targtPropOld == null) { new TranslatingException("Property " + property.ToString() + " could not be found in debugged module"); } targtMet = (isGetter ? targtProp.GetMethod : targtProp.SetMethod); targtMetOld = (isGetter ? targtPropOld.GetMethod : targtPropOld.SetMethod); SequencePointRemapper remapper = genSequencePointRemapper(targtMetOld, targtMet); // Translate tokens in methods IL code. MethodTranslator translator = new MethodTranslator(this); Dictionary <int, int> placeholder; MethodDescriptor log = translator.TranslateMethod(targtMet, targtMetOld, remapper, out placeholder); log.newRva = RVA; // Set method RVA. Manager.MetadataManager.OldEmitter.CorMetaDataEmit.SetRVA(targtMetOld.MetadataToken.ToUInt32(), RVA); // Store methods IL to buffer dIL.AddRange(log.codeIL); if (SymbolWriter != null) { SymbolWriter.EmitMethod(log.destToken, log.srcToken, placeholder); } }
/// <summary> /// Translate method IL to other metadata scope, with respect to original /// method specified by <c>originMethod</c>. /// (Registers local structures validly in sense of EnC, used for changing methods bodies by EnC) /// </summary> /// <param name="newMethod">Definition of the new version of the method.</param> /// <param name="originMethod">Definition of the last version of the method.</param> /// <param name="remapper">IL offset remapper, used to build local variable changes.</param> /// <param name="placeholder">Product of method, represents translation from old variable set to the new one.</param> /// <returns>Descriptor of the new version of method in IL.</returns> public MethodDescriptor TranslateMethod(MethodDefinition newMethod, MethodDefinition originMethod, SequencePointRemapper remapper, out Dictionary <int, int> placeholder) { MethodDescriptor log; log.destToken = originMethod.MetadataToken.ToUInt32(); log.srcToken = newMethod.MetadataToken.ToUInt32(); // build IL header log.localVarsToken = buildILHeader(newMethod, originMethod, remapper, out placeholder); // Add instructions processBody(newMethod, placeholder); log.newRva = 0; log.codeIL = buffer.ToArray(); buffer.Clear(); return(log); }
// +-----------------+ 0 // | delta header | ----->> size of the rest of IL in bytes // +-----------------+ 4 // | IL header | // +-----------------+ // | | // | IL code | // | | // +-----------------+ /// <summary> /// Builds header of changing method. /// </summary> /// <param name="newMethod">MethodDefinition of new version of changing method.</param> /// <param name="originMethod">MethoDefinition of original version of changing method.</param> /// <param name="tkMethod">Metadata token pointing to place of method in running version of metadata.</param> /// <param name="remapper">IL offset remapper, used to build local variable changes.</param> /// <param name="placeholder">Product of method, represents translation from old variable set to the new one.</param> /// <returns>Metadata token pointing to lolcalVars signature, if not present, 0 is given.</returns> private uint buildILHeader(MethodDefinition newMethod, MethodDefinition originMethod, SequencePointRemapper remapper, out Dictionary<int, int> placeholder) { uint local_var_old, token; uint local_var = newMethod.Body.LocalVarToken.ToUInt32(); uint code_size = (uint)newMethod.Body.CodeSize; uint max_stack_size = (uint)newMethod.Body.MaxStackSize; bool old_tiny = originMethod.Body.IsTiny; bool tiny = newMethod.Body.IsTiny; placeholder = null; if (old_tiny && !tiny) { // when new method is fat and the old tiny byte[] sig = metadata.NewImporter.GetSigantureSA(local_var); Signature signa = new Signature(sig); signa.Migrate(metadata); byte[] sig2 = signa.Compress(); metadata.OldEmitter.CorMetaDataEmit.GetTokenFromSig(sig2, (uint)sig2.Length, out token); tiny = false; } else if (!old_tiny && tiny) { // when new method is tiny and old fat local_var_old = originMethod.Body.LocalVarToken.ToUInt32(); local_var = local_var_old; max_stack_size = 8; tiny = false; } else if (!old_tiny && !tiny) { // both methods are fat Signature sigNew = new Signature(metadata.NewImporter.GetSigantureSA(local_var)); Signature sigOld = new Signature(metadata.OldImporter.GetSigantureSA(originMethod.Body.LocalVarToken.ToUInt32())); sigNew.Migrate(metadata); // Instead of unused old local variables use placeholders LocalVarDiff varDiff = new LocalVarDiff(Builder.Manager.ResourceManager.CurrentModule.SymReader, Builder.SymbolWriter.CorSymNewReader, remapper); byte[] sig = varDiff.makeSignature(sigOld, sigNew, out placeholder, originMethod.MetadataToken.ToUInt32(), newMethod.MetadataToken.ToUInt32(),metadata).Compress(); metadata.OldEmitter.CorMetaDataEmit.GetTokenFromSig(sig, (uint)sig.Length, out local_var); } //there is no need to change IL and MetaData when both methods are tiny if (!tiny) { uint header_flags = 0x3013; buffer.AddRange(BitConverter.GetBytes((ushort)header_flags));//BitConverter.GetBytes((ushort)header_flags));//.uintToByteArray(header_flags,2)); buffer.AddRange(BitConverter.GetBytes((ushort)max_stack_size));//Util.uintToByteArray(max_stack_size,2)); buffer.AddRange(BitConverter.GetBytes(code_size));//.uintToByteArray(code_size)); buffer.AddRange(BitConverter.GetBytes(local_var));//.uintToByteArray(local_var)); originMethod.Body.LocalVarToken = new MetadataToken(local_var); return local_var; } else { buffer.Add((byte)((code_size << 2) | 0x2)); return 0; } }
/// <summary> /// Translate method IL to other metadata scope, with respect to original /// method specified by <c>originMethod</c>. /// (Registers local structures validly in sense of EnC, used for changing methods bodies by EnC) /// </summary> /// <param name="newMethod">Definition of the new version of the method.</param> /// <param name="originMethod">Definition of the last version of the method.</param> /// <param name="remapper">IL offset remapper, used to build local variable changes.</param> /// <param name="placeholder">Product of method, represents translation from old variable set to the new one.</param> /// <returns>Descriptor of the new version of method in IL.</returns> public MethodDescriptor TranslateMethod(MethodDefinition newMethod, MethodDefinition originMethod, SequencePointRemapper remapper, out Dictionary<int, int> placeholder) { MethodDescriptor log; log.destToken = originMethod.MetadataToken.ToUInt32(); log.srcToken = newMethod.MetadataToken.ToUInt32(); // build IL header log.localVarsToken = buildILHeader(newMethod, originMethod, remapper, out placeholder); // Add instructions processBody(newMethod, placeholder); log.newRva = 0; log.codeIL = buffer.ToArray(); buffer.Clear(); return log; }
// +-----------------+ 0 // | delta header | ----->> size of the rest of IL in bytes // +-----------------+ 4 // | IL header | // +-----------------+ // | | // | IL code | // | | // +-----------------+ /// <summary> /// Builds header of changing method. /// </summary> /// <param name="newMethod">MethodDefinition of new version of changing method.</param> /// <param name="originMethod">MethoDefinition of original version of changing method.</param> /// <param name="tkMethod">Metadata token pointing to place of method in running version of metadata.</param> /// <param name="remapper">IL offset remapper, used to build local variable changes.</param> /// <param name="placeholder">Product of method, represents translation from old variable set to the new one.</param> /// <returns>Metadata token pointing to lolcalVars signature, if not present, 0 is given.</returns> private uint buildILHeader(MethodDefinition newMethod, MethodDefinition originMethod, SequencePointRemapper remapper, out Dictionary <int, int> placeholder) { uint local_var_old, token; uint local_var = newMethod.Body.LocalVarToken.ToUInt32(); uint code_size = (uint)newMethod.Body.CodeSize; uint max_stack_size = (uint)newMethod.Body.MaxStackSize; bool old_tiny = originMethod.Body.IsTiny; bool tiny = newMethod.Body.IsTiny; placeholder = null; if (old_tiny && !tiny) { // when new method is fat and the old tiny byte[] sig = metadata.NewImporter.GetSigantureSA(local_var); Signature signa = new Signature(sig); signa.Migrate(metadata); byte[] sig2 = signa.Compress(); metadata.OldEmitter.CorMetaDataEmit.GetTokenFromSig(sig2, (uint)sig2.Length, out token); tiny = false; } else if (!old_tiny && tiny) { // when new method is tiny and old fat local_var_old = originMethod.Body.LocalVarToken.ToUInt32(); local_var = local_var_old; max_stack_size = 8; tiny = false; } else if (!old_tiny && !tiny) { // both methods are fat Signature sigNew = new Signature(metadata.NewImporter.GetSigantureSA(local_var)); Signature sigOld = new Signature(metadata.OldImporter.GetSigantureSA(originMethod.Body.LocalVarToken.ToUInt32())); sigNew.Migrate(metadata); // Instead of unused old local variables use placeholders LocalVarDiff varDiff = new LocalVarDiff(Builder.Manager.ResourceManager.CurrentModule.SymReader, Builder.SymbolWriter.CorSymNewReader, remapper); byte[] sig = varDiff.makeSignature(sigOld, sigNew, out placeholder, originMethod.MetadataToken.ToUInt32(), newMethod.MetadataToken.ToUInt32(), metadata).Compress(); metadata.OldEmitter.CorMetaDataEmit.GetTokenFromSig(sig, (uint)sig.Length, out local_var); } //there is no need to change IL and MetaData when both methods are tiny if (!tiny) { uint header_flags = 0x3013; buffer.AddRange(BitConverter.GetBytes((ushort)header_flags)); //BitConverter.GetBytes((ushort)header_flags));//.uintToByteArray(header_flags,2)); buffer.AddRange(BitConverter.GetBytes((ushort)max_stack_size)); //Util.uintToByteArray(max_stack_size,2)); buffer.AddRange(BitConverter.GetBytes(code_size)); //.uintToByteArray(code_size)); buffer.AddRange(BitConverter.GetBytes(local_var)); //.uintToByteArray(local_var)); originMethod.Body.LocalVarToken = new MetadataToken(local_var); return(local_var); } else { buffer.Add((byte)((code_size << 2) | 0x2)); return(0); } }
public LocalVarDiff(ISymUnmanagedReader oldReader, ISymUnmanagedReader newReader, SequencePointRemapper remapper) { this.remapper = remapper; this.oldReader = oldReader; this.newReader = newReader; }
/// <summary> /// Creates <see cref="SequencePointRemapper">SequencePointRemapper</see> - sequence point difference tool for /// specified method used in debug state refreshing and local variables definition. /// </summary> /// <param name="methodDef">Method to which generating takes place.</param> /// <returns>Instance of <see cref="SequencePointRemapper">SequencePointRemapper</see>.</returns> private SequencePointRemapper genSequencePointRemapper(MethodDefinition methodDefOld, MethodDefinition methodDefNew) { uint token = methodDefOld.MetadataToken.ToUInt32(); List<SequencePoint> oldSeqs = SymbolWriterClass.GetMethodSequencePoints( Manager.ResourceManager.CurrentModule.SymReader, methodDefOld.MetadataToken.ToUInt32()); List<SequencePoint> newSeqs = SymbolWriterClass.GetMethodSequencePoints( SymbolWriter.CorSymNewReader, methodDefNew.MetadataToken.ToUInt32()); SequencePointRemapper remapper = new SequencePointRemapper(oldSeqs, newSeqs, Manager.ActualEditEvent.sourceTextChanges[token]); SequencePointRemappers.Add(token, remapper); return remapper; }