C
C#2y ago
mini

Harmony throws unknown location exception on Patch

I am using Harmony to add a parameter to various log calls of the assembly but whenever I try to Patch it by transpiling it, I get an error:
IL Compile Error (unknown location)
bei HarmonyLib.PatchFunctions.UpdateWrapper(MethodBase original, PatchInfo patchInfo)
bei HarmonyLib.PatchProcessor.Patch()
bei HarmonyLib.Harmony.Patch(MethodBase original, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer, HarmonyMethod ilmanipulator)
IL Compile Error (unknown location)
bei HarmonyLib.PatchFunctions.UpdateWrapper(MethodBase original, PatchInfo patchInfo)
bei HarmonyLib.PatchProcessor.Patch()
bei HarmonyLib.Harmony.Patch(MethodBase original, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer, HarmonyMethod ilmanipulator)
Does anyone have an idea why?
9 Replies
Monsieur Wholesome
Ask in their server instead? This is off the standard C# development tbh
mini
mini2y ago
This is completely C# related and exactly what this server is for, I don't really understand your advice to not ask here
Mayor McCheese
It might be how the compiler has optimized code to where something is breaking so it's trying to patch a method that has been inlined for instance
mini
mini2y ago
I've been looking into the IL code using dnspy If I 1:1 apply the changes my code does with dnspy everything does fine
List<CodeInstruction> instructions = _instructions.ToList();

instructions[66] = new CodeInstruction(instructions[56].opcode, instructions[56].operand);
instructions.Insert(66, new CodeInstruction(OpCodes.Ldc_R4, 4));

for (int i = 50; i < 70; i++)
{
Console.WriteLine($"Instruction at index {i}");
Console.WriteLine(instructions[i].opcode);
Console.WriteLine(instructions[i].operand);
}

return instructions;
List<CodeInstruction> instructions = _instructions.ToList();

instructions[66] = new CodeInstruction(instructions[56].opcode, instructions[56].operand);
instructions.Insert(66, new CodeInstruction(OpCodes.Ldc_R4, 4));

for (int i = 50; i < 70; i++)
{
Console.WriteLine($"Instruction at index {i}");
Console.WriteLine(instructions[i].opcode);
Console.WriteLine(instructions[i].operand);
}

return instructions;
I replaced the instruction at index 66 with the instruction at index 56 and then added a 4 as a parameter to the method call then I'm printing out the instructions around that change I opened dnspy and 1:1 made sure the IL code written out matches the one in the IL editor in dnspy and then saved it in dnspy dnspy successfully applied the change I kind of have a feeling that this is not related to the change itself I am making but rather to something I didn't set up properly or called properly with harmony
Mayor McCheese
could be, esp. if you are able to edit in alternative methodology I don't know much about harmony itself; so I can't really say
mini
mini2y ago
Harmony harmony = new Harmony("patch");

MethodInfo logPatch = typeof(Patch).GetMethod(nameof(LogPatch), BindingFlags.Static | BindingFlags.NonPublic);
harmony.Patch(method, transpiler: new HarmonyMethod(logPatch));

private static IEnumerable<CodeInstruction> LogPatch(IEnumerable<CodeInstruction> _instructions)
{
List<CodeInstruction> instructions = _instructions.ToList();

instructions[66] = new CodeInstruction(instructions[56].opcode, instructions[56].operand);
instructions.Insert(66, new CodeInstruction(OpCodes.Ldc_R4, 4));
for (int i = 50; i < 70; i++)
{
Console.WriteLine($"Instruction at index {i}");
Console.WriteLine(instructions[i].opcode);
Console.WriteLine(instructions[i].operand);
}

return instructions;
}
Harmony harmony = new Harmony("patch");

MethodInfo logPatch = typeof(Patch).GetMethod(nameof(LogPatch), BindingFlags.Static | BindingFlags.NonPublic);
harmony.Patch(method, transpiler: new HarmonyMethod(logPatch));

private static IEnumerable<CodeInstruction> LogPatch(IEnumerable<CodeInstruction> _instructions)
{
List<CodeInstruction> instructions = _instructions.ToList();

instructions[66] = new CodeInstruction(instructions[56].opcode, instructions[56].operand);
instructions.Insert(66, new CodeInstruction(OpCodes.Ldc_R4, 4));
for (int i = 50; i < 70; i++)
{
Console.WriteLine($"Instruction at index {i}");
Console.WriteLine(instructions[i].opcode);
Console.WriteLine(instructions[i].operand);
}

return instructions;
}
this is the whole code related to this
Mayor McCheese
If you're going the manual patch route the inlining shouldn't matter either way My experience is limited here, sorry 😦
mikernet
mikernet2y ago
Are there any references to instruction 66 before you replaced it, i.e. a jump to it or something? Because then you gotta update those as well, I believe. An instruction can be the operand for another instruction "unknown location" makes me think something else is pointing to the instruction at 66 for a jump so it can't "find the location" of the instruction in the method because it doesnt exist in the method anymore
mini
mini2y ago
I'm already talking to people on the harmony discord, we already went so far to only override the operand and not the opcode there aren't any jumps to it