Esempio n. 1
0
        public void CanGetInstructionsWithNoILGenerator()
        {
            var method      = typeof(Class12).GetMethod(nameof(Class12.FizzBuzz));
            var instrsNoGen = MethodBodyReader.GetInstructions(generator: null, method);

            var dynamicMethod = DynamicTools.CreateDynamicMethod(method, "_Patch");
            var instrsHasGen  = MethodBodyReader.GetInstructions(dynamicMethod.GetILGenerator(), method);

            Assert.AreEqual(instrsNoGen.Count, instrsHasGen.Count);
            for (var i = 0; i < instrsNoGen.Count; i++)
            {
                var instrNoGen  = instrsNoGen[i];
                var instrHasGen = instrsHasGen[i];
                Assert.AreEqual(instrNoGen.offset, instrHasGen.offset, "offset @ {0} ({1})", i, instrNoGen);
                Assert.AreEqual(instrNoGen.opcode, instrHasGen.opcode, "opcode @ {0} ({1})", i, instrNoGen);
                AssertAreEqual(instrNoGen.operand, instrHasGen.operand, "operand", i, instrNoGen);
                CollectionAssert.AreEqual(instrNoGen.labels, instrHasGen.labels, "labels @ {0}", i);
                CollectionAssert.AreEqual(instrNoGen.blocks, instrHasGen.blocks, "blocks @ {0}", i);
                AssertAreEqual(instrNoGen.operand, instrHasGen.operand, "argument", i, instrNoGen);

                // The only difference between w/o gen and w/ gen is this:
                var operandType = instrNoGen.opcode.OperandType;
                if ((operandType == OperandType.ShortInlineVar || operandType == OperandType.InlineVar) && !(instrNoGen.argument is null))
                {
                    Assert.AreEqual(typeof(LocalVariableInfo), instrNoGen.argument.GetType(), "w/o generator argument type @ {0} ({1})", i, instrNoGen);
                    Assert.AreEqual(typeof(LocalBuilder), instrHasGen.argument.GetType(), "w/ generator argument type @ {0} ({1})", i, instrNoGen);
                }
            }
        }
        /// <summary>
        /// Checks if the given method has a IL instruction that SETS a persistent field
        /// </summary>
        private static bool MethodSetsPersistentField(MethodBase partModuleMethod)
        {
            var method       = DynamicTools.CreateDynamicMethod(partModuleMethod, "read");
            var instructions = MethodBodyReader.GetInstructions(method.GetILGenerator(), partModuleMethod);

            //OpCodes.Stfld is the opcode for SETTING the value of a field
            foreach (var instruction in instructions.Where(i => i.opcode == OpCodes.Stfld))
            {
                if (!(instruction.operand is FieldInfo operand))
                {
                    continue;
                }
                if (FieldIsIgnored(operand))
                {
                    continue;
                }

                var attributes = operand.GetCustomAttributes(typeof(KSPField), false).Cast <KSPField>().ToArray();
                if (attributes.Any() && attributes.First().isPersistant)
                {
                    return(true);
                }
            }

            return(false);
        }
Esempio n. 3
0
        static HaulToBlueprintUnderRock()
        {
            //AccessTools.Inner
            HarmonyMethod   transpiler       = new HarmonyMethod(typeof(DeliverUnderRock), nameof(DeliverUnderRock.Transpiler));
            HarmonyInstance harmony          = HarmonyInstance.Create("Uuugggg.rimworld.Replace_Stuff.main");
            MethodInfo      CanConstructInfo = AccessTools.Method(typeof(GenConstruct), "CanConstruct");


            //Find the compiler-created method in Toils_Haul that calls CanConstruct
            List <Type> nestedTypes = new List <Type>(typeof(Toils_Haul).GetNestedTypes(BindingFlags.NonPublic));

            while (!nestedTypes.NullOrEmpty())
            {
                Type type = nestedTypes.Pop();
                nestedTypes.AddRange(type.GetNestedTypes(BindingFlags.NonPublic));

                foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic))
                {
                    if (method.DeclaringType != type)
                    {
                        continue;
                    }

                    DynamicMethod dm = DynamicTools.CreateDynamicMethod(method, "-unused");

                    if (Harmony.ILCopying.MethodBodyReader.GetInstructions(dm.GetILGenerator(), method).
                        Any(ilcode => ilcode.operand == CanConstructInfo))
                    {
                        harmony.Patch(method, null, null, transpiler);
                    }
                }
            }
        }
Esempio n. 4
0
        //WorkGiver_Grower has one PotentialWorkCellsGlobal for both subclasses
        //public override IEnumerable<IntVec3> PotentialWorkCellsGlobal(Pawn pawn)Thing t, HashSet<Thing> nearbyNeeders, IConstructible constructible, Pawn pawn)

        static DoNotHarvest_Building()
        {
            HarmonyMethod   transpiler = new HarmonyMethod(typeof(DoNotHarvest_Building), nameof(DoNotHarvest_Building.Transpiler));
            HarmonyInstance harmony    = HarmonyInstance.Create("Uuugggg.rimworld.TD_Enhancement_Pack.main");

            MethodInfo IsForbiddenInfo    = AccessTools.Method(typeof(ForbidUtility), "IsForbidden", new Type[] { typeof(Thing), typeof(Pawn) });
            Func <MethodInfo, bool> check = delegate(MethodInfo method)
            {
                DynamicMethod dm = DynamicTools.CreateDynamicMethod(method, "-unused");

                return(Harmony.ILCopying.MethodBodyReader.GetInstructions(dm.GetILGenerator(), method).
                       Any(ilcode => ilcode.operand == IsForbiddenInfo));
            };

            harmony.PatchGeneratedMethod(typeof(WorkGiver_Grower), check, transpiler: transpiler);
        }
        static HaulToBlueprintUnderRock()
        {
            HarmonyMethod   transpiler = new HarmonyMethod(typeof(DeliverUnderRock), nameof(DeliverUnderRock.Transpiler));
            HarmonyInstance harmony    = HarmonyInstance.Create("Uuugggg.rimworld.Replace_Stuff.main");

            MethodInfo             CanConstructInfo = AccessTools.Method(typeof(GenConstruct), "CanConstruct");
            Predicate <MethodInfo> check            = delegate(MethodInfo method)
            {
                DynamicMethod dm = DynamicTools.CreateDynamicMethod(method, "-unused");

                return(Harmony.ILCopying.MethodBodyReader.GetInstructions(dm.GetILGenerator(), method).
                       Any(ilcode => ilcode.operand == CanConstructInfo));
            };

            harmony.PatchGeneratedMethod(typeof(Toils_Haul), check, transpiler: transpiler);
        }
Esempio n. 6
0
        static PriorityCareJobFail()
        {
            HarmonyMethod   transpiler = new HarmonyMethod(typeof(PriorityCareJobFail), nameof(Transpiler));
            HarmonyInstance harmony    = HarmonyInstance.Create("uuugggg.rimworld.SmartMedicine.main");

            MethodInfo AllowsMedicineInfo = AccessTools.Method(typeof(MedicalCareUtility), "AllowsMedicine");

            Predicate <MethodInfo> check = delegate(MethodInfo method)
            {
                DynamicMethod dm = DynamicTools.CreateDynamicMethod(method, "-unused");

                return(Harmony.ILCopying.MethodBodyReader.GetInstructions(dm.GetILGenerator(), method)
                       .Any(ilcode => ilcode.operand == AllowsMedicineInfo));
            };

            harmony.PatchGeneratedMethod(typeof(JobDriver_TendPatient), check, transpiler: transpiler);
        }
Esempio n. 7
0
        /// <summary>
        /// Checks if the given method has a IL instruction that SETS (therefore, it changes the value) a customized field
        /// </summary>
        private static IEnumerable <FieldInfo> GetCustomizedFieldsChangedByMethod(MethodBase partModuleMethod, ModuleDefinition definition)
        {
            var listOfFields = new HashSet <FieldInfo>();

            var method       = DynamicTools.CreateDynamicMethod(partModuleMethod, "read");
            var instructions = MethodBodyReader.GetInstructions(method.GetILGenerator(), partModuleMethod);

            //OpCodes.Stfld is the opcode for SETTING the value of a field
            foreach (var instruction in instructions.Where(i => i.opcode == OpCodes.Stfld))
            {
                if (!(instruction.operand is FieldInfo operand))
                {
                    continue;
                }

                if (definition.Fields.Any(f => f.FieldName == operand.Name))
                {
                    listOfFields.Add(operand);
                }
            }

            return(listOfFields);
        }
Esempio n. 8
0
        public static void DoHotSwap()
        {
            foreach (var kv in AssemblyFiles)
            {
                var asm    = kv.Key;
                var module = asm.GetModules()[0];

                using (var dnModule = ModuleDefMD.Load(kv.Value.FullName))
                {
                    foreach (var dnType in dnModule.GetTypes())
                    {
                        if (!dnType.HasCustomAttributes ||
                            !dnType.CustomAttributes.Select(a => a.AttributeType.Name).Any(n => n == "HotSwappable" || n == "HotSwappableAttribute")
                            )
                        {
                            continue;
                        }

                        var type  = Type.GetType(dnType.AssemblyQualifiedName);
                        var flags = BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;

                        foreach (var method in type.GetMethods(flags))
                        {
                            if (method.GetMethodBody() == null)
                            {
                                continue;
                            }

                            byte[] code     = method.GetMethodBody().GetILAsByteArray();
                            var    dnMethod = dnType.Methods.FirstOrDefault(m => MethodsSame(method, m));

                            var    methodBody = dnMethod.Body;
                            byte[] newCode    = SerializeInstructions(methodBody);

                            if (code.SequenceEqual(newCode))
                            {
                                continue;
                            }

                            Log.Message("Patching " + method.FullDescription());

                            var replacement = DynamicTools.CreateDynamicMethod(method, $"_HotSwap{count++}");
                            var ilGen       = replacement.GetILGenerator();

                            foreach (var local in methodBody.Variables)
                            {
                                var localType = Type.GetType(local.Type.AssemblyQualifiedName);
                                //Log.Message($"local {local.Type.AssemblyQualifiedName} / {localType}");

                                ilGen.DeclareLocal(localType);
                            }

                            int pos = 0;

                            foreach (var inst in methodBody.Instructions)
                            {
                                switch (inst.OpCode.OperandType)
                                {
                                case dnlib.DotNet.Emit.OperandType.InlineString:
                                case dnlib.DotNet.Emit.OperandType.InlineType:
                                case dnlib.DotNet.Emit.OperandType.InlineMethod:
                                case dnlib.DotNet.Emit.OperandType.InlineField:
                                case dnlib.DotNet.Emit.OperandType.InlineSig:
                                case dnlib.DotNet.Emit.OperandType.InlineTok:
                                    pos += inst.OpCode.Size;
                                    object refe = TranslateRef(module, inst.Operand);
                                    if (refe == null)
                                    {
                                        Log.Message($"Null reference {inst.Operand} {inst.Operand.GetType()}");
                                    }

                                    int token = replacement.AddRef(refe);
                                    newCode[pos++] = (byte)(token & 255);
                                    newCode[pos++] = (byte)(token >> 8 & 255);
                                    newCode[pos++] = (byte)(token >> 16 & 255);
                                    newCode[pos++] = (byte)(token >> 24 & 255);

                                    break;

                                default:
                                    pos += inst.GetSize();
                                    break;
                                }
                            }

                            ilGen.code      = newCode;
                            ilGen.code_len  = newCode.Length;
                            ilGen.max_stack = methodBody.MaxStack;

                            var exhandlers  = methodBody.ExceptionHandlers.Distinct(new ExceptionHandlerComparer()).ToArray();
                            var ex_handlers = ilGen.ex_handlers = new ILExceptionInfo[exhandlers.Length];

                            for (int i = 0; i < exhandlers.Length; i++)
                            {
                                var ex    = exhandlers[i];
                                int start = (int)ex.TryStart.Offset;
                                int end   = (int)ex.TryEnd.Offset;
                                int len   = end - start;

                                var handlers = methodBody.ExceptionHandlers.Where(h => h.TryStart.Offset == start).ToArray();

                                ex_handlers[i].start    = start;
                                ex_handlers[i].len      = len;
                                ex_handlers[i].handlers = new ILExceptionBlock[handlers.Length];

                                for (int j = 0; j < handlers.Length; j++)
                                {
                                    var exx = handlers[j];

                                    int handlerStart = (int)exx.HandlerStart.Offset;
                                    int handlerEnd   = (int)exx.HandlerEnd.Offset;
                                    int handlerLen   = handlerEnd - handlerStart;

                                    Type catchType    = null;
                                    int  filterOffset = 0;

                                    if (exx.CatchType != null)
                                    {
                                        catchType = module.ResolveType(exx.CatchType.MDToken.ToInt32());
                                    }
                                    else if (exx.FilterStart != null)
                                    {
                                        filterOffset = (int)exx.FilterStart.Offset;
                                    }

                                    var arr = ilGen.ex_handlers[i].handlers;
                                    arr[j].type          = (int)ex.HandlerType;
                                    arr[j].start         = handlerStart;
                                    arr[j].len           = handlerLen;
                                    arr[j].extype        = catchType;
                                    arr[j].filter_offset = filterOffset;
                                }
                            }

                            Log.Message("Preparing method");

                            DynamicTools.PrepareDynamicMethod(replacement);

                            Log.Message("Detouring");

                            dynMethods[method] = replacement;
                            Memory.DetourMethod(method, replacement);

                            Log.Message("Patch done");
                        }
                    }
                }
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Compiles a method into IL instructions.
        /// </summary>
        /// <param name="method">Method to compile.</param>
        /// <returns>
        /// List of ILInstructions.
        /// </returns>
        /// <remarks>
        /// Utilizes harmony library.
        /// </remarks>
        public static List <CodeInstruction> MethodToILInstructions(MethodBase method)
        {
            DynamicMethod dynamicMethod = DynamicTools.CreateDynamicMethod(method, "_ILParser");

            if (dynamicMethod == null)
            {
                return(null);
            }

            // Get il generato
            ILGenerator il = dynamicMethod.GetILGenerator();

            LocalBuilder[] existingVariables = DynamicTools.DeclareLocalVariables(method, il);
            Dictionary <string, LocalBuilder> privateVars = new Dictionary <string, LocalBuilder>();

            MethodBodyReader reader = new MethodBodyReader(method, il);

            reader.DeclareVariables(existingVariables);
            reader.ReadInstructions();

            List <ILInstruction> ilInstructions = (List <ILInstruction>)FIilInstructions.GetValue(reader);

            // Defines function start label
            il.DefineLabel();

            // Define labels
            foreach (ILInstruction ilInstruction in ilInstructions)
            {
                switch (ilInstruction.opcode.OperandType)
                {
                case OperandType.InlineSwitch:
                {
                    ILInstruction[] array = ilInstruction.operand as ILInstruction[];
                    if (array != null)
                    {
                        List <Label>    labels = new List <Label>();
                        ILInstruction[] array2 = array;
                        foreach (ILInstruction iLInstruction2 in array2)
                        {
                            Label item = il.DefineLabel();
                            iLInstruction2.labels.Add(item);
                            labels.Add(item);
                        }
                        ilInstruction.argument = labels.ToArray();
                    }
                    break;
                }

                case OperandType.InlineBrTarget:
                case OperandType.ShortInlineBrTarget:
                {
                    ILInstruction iLInstruction = ilInstruction.operand as ILInstruction;
                    if (iLInstruction != null)
                    {
                        Label label2 = il.DefineLabel();
                        iLInstruction.labels.Add(label2);
                        ilInstruction.argument = label2;
                    }
                    break;
                }
                }
            }

            // Transpile code
            CodeTranspiler         codeTranspiler = new CodeTranspiler(ilInstructions);
            List <CodeInstruction> result         = codeTranspiler.GetResult(il, method);

            // Replace debug commands with normal
            foreach (CodeInstruction codeInstruction in result)
            {
                OpCode opCode = codeInstruction.opcode;

                codeInstruction.opcode = ReplaceShortJumps(opCode);
            }

            return(result);
        }