Skip to content

Commit

Permalink
CecilEmitter.Dump: Adding test for ILLabel dumping
Browse files Browse the repository at this point in the history
  • Loading branch information
kohanis authored and ManlyMarco committed Jan 10, 2025
1 parent c4392ee commit 6746d17
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 15 deletions.
37 changes: 22 additions & 15 deletions Harmony/Internal/Util/CecilEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,33 @@ internal static class CecilEmitter
typeof(UnverifiableCodeAttribute).GetConstructor(Type.EmptyTypes);

public static void Dump(MethodDefinition md, IEnumerable<string> dumpPaths, MethodBase original = null)
{
using var module = DumpImpl(md, original);

foreach (var settingsDumpPath in dumpPaths)
{
var fullPath = Path.GetFullPath(settingsDumpPath);
try
{
Directory.CreateDirectory(fullPath);
using var stream = File.OpenWrite(Path.Combine(fullPath, $"{module.Name}.dll"));
module.Write(stream);
}
catch (Exception e)
{
Logger.Log(Logger.LogChannel.Error, () => $"Failed to dump {md.GetID(simple: true)} to {fullPath}: {e}");
}
}
}

internal static ModuleDefinition DumpImpl(MethodDefinition md, MethodBase original = null)
{
if(md.Body is null)
throw new ArgumentException($"Body of MethodDefinition '{md.Name}' to dump is null");

var name = $"HarmonyDump.{SanitizeTypeName(md.GetID(withType: false, simple: true))}.{Guid.NewGuid().GetHashCode():X8}";
var originalName = (original?.Name ?? md.Name).Replace('.', '_');
using var module = ModuleDefinition.CreateModule(name,
var module = ModuleDefinition.CreateModule(name,
new ModuleParameters
{
Kind = ModuleKind.Dll, ReflectionImporterProvider = MMReflectionImporter.ProviderNoDefault
Expand Down Expand Up @@ -114,20 +134,7 @@ public static void Dump(MethodDefinition md, IEnumerable<string> dumpPaths, Meth
new ParameterDefinition("<>_this", ParameterAttributes.None, type.Relink(relinker, clone)));
}

foreach (var settingsDumpPath in dumpPaths)
{
var fullPath = Path.GetFullPath(settingsDumpPath);
try
{
Directory.CreateDirectory(fullPath);
using var stream = File.OpenWrite(Path.Combine(fullPath, $"{module.Name}.dll"));
module.Write(stream);
}
catch (Exception e)
{
Logger.Log(Logger.LogChannel.Error, () => $"Failed to dump {md.GetID(simple: true)} to {fullPath}: {e}");
}
}
return module;
}

private static string SanitizeTypeName(string typeName)
Expand Down
36 changes: 36 additions & 0 deletions HarmonyTests/Extras/Dump.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using HarmonyLib.Internal.Util;
using HarmonyLibTests;
using MonoMod.Cil;
using MonoMod.Utils;
using NUnit.Framework;
using System;
using System.Linq;


namespace HarmonyTests.Extras;

[TestFixture]
public class Dump : TestLogger
{
[Test]
public void Test_DumpIlLabel()
{
using var dmd = new DynamicMethodDefinition("DumpIlLabelTestMethod", typeof(void), Type.EmptyTypes);
var il = new ILContext(dmd.Definition);
var cur = new ILCursor(il);

var label = cur.DefineLabel();
cur.EmitBr(label);
cur.EmitRet();
label.Target = cur.Prev;

var method = cur.Method;

using var dumpedModule = CecilEmitter.DumpImpl(method);
var dumpedMethod = dumpedModule.Types.SelectMany(i => i.Methods).FirstOrDefault();
Assert.NotNull(dumpedMethod);

var instructions = dumpedMethod!.Body.Instructions;
Assert.True(instructions[0].Operand == instructions[1]);
}
}

0 comments on commit 6746d17

Please sign in to comment.