Skip to content

Commit

Permalink
Refactor ScubaDiver project (#14)
Browse files Browse the repository at this point in the history
* [third_party/ScubaDiver] Handle bootstrapper unloading in DLL entrypoint

* [third_party/ScubaDiver] Migrate ClrMD methods to SnapshotService class

* [MTGOSDK/Core/Remoting/Interop] Move ParseType method to TypeDump class

* [MTGOSDK/Core/Reflection] Migrate ClrMD snapshot runtime

* [third_party/ScubaDiver] Fix deadlock starting diver host

* [MTGOSDK/Resources] Migrate Bootstrapper

Move Bootstrapper class to resources namespace, removing conditional namespace imports for `MTGOSDK.Core`.
  • Loading branch information
Qonfused authored May 6, 2024
1 parent a659a2f commit fe14836
Show file tree
Hide file tree
Showing 34 changed files with 1,034 additions and 832 deletions.
8 changes: 8 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
<_MTGOSDKCorePath>$(SolutionDir)\MTGOSDK\bin\$(Configuration)\$(_MTGOSDKCoreTFM)</_MTGOSDKCorePath>
</PropertyGroup>

<!-- Debugging Options -->
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>

<!-- Continuous Integration -->
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
Expand Down
2 changes: 2 additions & 0 deletions Directory.Packages.Props
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
<!-- MTGOSDK -->
<PackageVersion Include="Microsoft.CSharp"
Version="4.7.0" />
<PackageVersion Include="System.Reflection.Emit.Lightweight"
Version="4.7.0" />
<PackageVersion Include="Microsoft.Diagnostics.Runtime"
Version="3.1.512801" />
<PackageVersion Include="ImpromptuInterface"
Expand Down
23 changes: 12 additions & 11 deletions MTGOSDK.MSBuild/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -613,17 +613,6 @@
"System.Runtime": "4.3.0"
}
},
"System.Reflection.Emit.Lightweight": {
"type": "Transitive",
"resolved": "4.3.0",
"contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==",
"dependencies": {
"System.Reflection": "4.3.0",
"System.Reflection.Emit.ILGeneration": "4.3.0",
"System.Reflection.Primitives": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Reflection.Extensions": {
"type": "Transitive",
"resolved": "4.3.0",
Expand Down Expand Up @@ -1124,6 +1113,18 @@
"System.Security.Principal.Windows": "5.0.0"
}
},
"System.Reflection.Emit.Lightweight": {
"type": "CentralTransitive",
"requested": "[4.7.0, )",
"resolved": "4.3.0",
"contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==",
"dependencies": {
"System.Reflection": "4.3.0",
"System.Reflection.Emit.ILGeneration": "4.3.0",
"System.Reflection.Primitives": "4.3.0",
"System.Runtime": "4.3.0"
}
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "CentralTransitive",
"requested": "[6.0.0, )",
Expand Down
34 changes: 34 additions & 0 deletions MTGOSDK.Win32/src/API/Kernel32/ProcessShapshot/PssFreeSnapshot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/** @file
Copyright (c) 2024, Cory Bennett. All rights reserved.
SPDX-License-Identifier: Apache-2.0
**/

using System;
using System.Runtime.InteropServices;


namespace MTGOSDK.Win32.API;

public static partial class Kernel32
{
/// <summary>
/// Frees a snapshot of the address space of a process.
/// </summary>
[DllImport("kernel32")] // SetLastError=true ?
public static extern int PssFreeSnapshot(
/// <summary>
/// A handle to the process that contains the snapshot.
/// </summary>
/// <remarks>
/// The handle must have the PROCESS_VM_READ, PROCESS_VM_OPERATION,
/// and PROCESS_DUP_HANDLE rights. If the snapshot was captured from the
/// current process, or duplicated into the current process, then pass in
/// the result of <see cref="GetCurrentProcess"/>.
/// </remarks>
[In] IntPtr ProcessHandle,
/// <summary>
/// A handle to the snapshot to be freed.
/// </summary>
[In] IntPtr SnapshotHandle
);
}
9 changes: 6 additions & 3 deletions MTGOSDK/MTGOSDK.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);
<!-- Disables unenforcable nullable warnings - breaks static analysis -->
CS8597;CS8600;CS8602;CS8603;CS8604;CS8625;CS8767;CS9113;IDE0065;
CS8597;CS8600;CS8602;CS8603;CS8604;CS8625;CS8629;CS8767;CS9113;IDE0065;
<!-- Disable warnings for incompatible TFMs required for building -->
NU1702;MSB3277;
<!-- FIXME: From RemoteNET library -->
CS8601;CS8608;CS8610;CS8618;CS8619;CS8620;CS8765;
CS8601;CS8605;CS8608;CS8610;CS8618;CS8619;CS8620;CS8765;
</NoWarn>
<!-- Allows access to raw pointers for performance-critical IL building -->
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<!-- Import MTGOSDK package properties -->
Expand All @@ -23,7 +25,8 @@
Condition="'$(TargetFramework)' != '$(_MTGOSDKCoreTFM)'" />

<ItemGroup>
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="System.Reflection.Emit.Lightweight" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" />
<PackageReference Include="ImpromptuInterface" />
<PackageReference Include="Newtonsoft.Json" />
Expand Down
15 changes: 15 additions & 0 deletions MTGOSDK/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@
"resolved": "13.0.3",
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
},
"System.Reflection.Emit.Lightweight": {
"type": "Direct",
"requested": "[4.7.0, )",
"resolved": "4.7.0",
"contentHash": "a4OLB4IITxAXJeV74MDx49Oq2+PsF6Sml54XAFv+2RyWwtDBcabzoxiiJRhdhx+gaohLh4hEGCLQyBozXoQPqA==",
"dependencies": {
"System.Reflection.Emit.ILGeneration": "4.7.0"
}
},
"Dynamitey": {
"type": "Transitive",
"resolved": "3.0.3",
Expand Down Expand Up @@ -394,6 +403,12 @@
"resolved": "13.0.3",
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
},
"System.Reflection.Emit.Lightweight": {
"type": "Direct",
"requested": "[4.7.0, )",
"resolved": "4.7.0",
"contentHash": "a4OLB4IITxAXJeV74MDx49Oq2+PsF6Sml54XAFv+2RyWwtDBcabzoxiiJRhdhx+gaohLh4hEGCLQyBozXoQPqA=="
},
"Dynamitey": {
"type": "Transitive",
"resolved": "3.0.3",
Expand Down
2 changes: 2 additions & 0 deletions MTGOSDK/src/Core/Reflection/DLRWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

using System.Collections.Concurrent;

using MTGOSDK.Core.Remoting;


namespace MTGOSDK.Core.Reflection;
using static Attributes;
Expand Down
107 changes: 107 additions & 0 deletions MTGOSDK/src/Core/Reflection/Emit/Converter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/** @file
Copyright (c) 2021, Xappy.
Copyright (c) 2024, Cory Bennett. All rights reserved.
SPDX-License-Identifier: Apache-2.0 and MIT
**/

using System;
using System.Reflection.Emit;

using MTGOSDK.Core.Remoting.Interop.Extensions;


namespace MTGOSDK.Core.Reflection.Emit;

/// <summary>
/// A class that converts an IntPtr to an object reference.
/// </summary>
public class Converter<T>
{
/// <summary>
/// The delegate that converts an IntPtr to an object reference.
/// </summary>
delegate U Void2ObjectConverter<U>(IntPtr pManagedObject);

/// <summary>
/// The converter instance that converts an IntPtr to an object reference.
/// </summary>
private static Void2ObjectConverter<T> myConverter;

static Converter()
{
//
// The type initializer is run every time the converter is instantiated
// using a different generic argument.
//
GenerateDynamicMethod();
}

/// <summary>
/// Generates a dynamic method that converts an IntPtr to an object reference.
/// </summary>
/// <remarks>
/// The dynamic method trick is discussed originally by Alois Kraus here:
/// https://social.microsoft.com/Forums/windows/en-US/06ac44b0-30d8-44a1-86a4-1716dc431c62/how-to-convert-an-intptr-to-an-object-in-c?forum=clr
/// </remarks>
static void GenerateDynamicMethod()
{
if (myConverter == null)
{
DynamicMethod method = new("ConvertPtrToObjReference",
typeof(T),
new Type[] { typeof(IntPtr) },
typeof(IntPtr),
true);
var gen = method.GetILGenerator();
// Load first argument
gen.Emit(OpCodes.Ldarg_0);
// Return it directly. The Clr will take care of the cast!
// This construct is unverifiable so we need to plug this into an assembly
// with IL Verification disabled.
gen.Emit(OpCodes.Ret);
myConverter = (Void2ObjectConverter<T>)method
.CreateDelegate(typeof(Void2ObjectConverter<T>));
}
}

/// <summary>
/// Handles the conversion of an IntPtr to an object reference.
/// </summary>
/// <param name="pObj">The IntPtr to convert.</param>
/// <param name="expectedMethodTable">The expected method table of the object.</param>
/// <returns>The object reference.</returns>
/// <exception cref="ArgumentException">
/// Thrown when the actual method table value is not as expected.
/// </exception>
/// <remarks>
/// This methods reads the method table of the object to make sure we aren't
/// mistakenly pointing at another type by now (could be caused by the GC).
/// </remarks>
public T ConvertFromIntPtr(IntPtr pObj, IntPtr expectedMethodTable)
{
IntPtr actualMethodTable = pObj.GetMethodTable();
if (actualMethodTable != expectedMethodTable)
{
throw new ArgumentException("Actual Method Table value was not as expected");
}
return myConverter(pObj);
}

/// <summary>
/// Handles the conversion of an IntPtr to an object reference.
/// </summary>
/// <param name="pObj">The IntPtr to convert.</param>
/// <param name="expectedMethodTable">The expected method table of the object.</param>
/// <returns>The object reference.</returns>
/// <exception cref="ArgumentException">
/// Thrown when the actual method table value is not as expected.
/// </exception>
/// <remarks>
/// This methods reads the method table of the object to make sure we aren't
/// mistakenly pointing at another type by now (could be caused by the GC).
/// </remarks>
public T ConvertFromIntPtr(ulong pObj, ulong expectedMethodTable) =>
ConvertFromIntPtr(
new IntPtr((long) pObj),
new IntPtr((long) expectedMethodTable));
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
using System.Threading;


namespace ScubaDiver;
namespace MTGOSDK.Core.Reflection.Emit;

public static class FreezeFuncsFactory
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using System.Threading.Tasks;


namespace ScubaDiver;
namespace MTGOSDK.Core.Reflection.Emit;

public class FrozenObjectsCollection
{
Expand Down Expand Up @@ -81,13 +81,13 @@ public ulong Pin(object o)
object[] objs = _frozenObjects.Keys.Concat(new object[] { o }).ToArray();
PinInternal(objs);

Logger.Debug($"[{nameof(FrozenObjectsCollection)}] Pinned another object. Num Pinned: {_frozenObjects.Count}");
// Logger.Debug($"[{nameof(FrozenObjectsCollection)}] Pinned another object. Num Pinned: {_frozenObjects.Count}");

return _frozenObjects[o];
}
}

public bool TryGetPinnedObject(ulong addr, out object o)
public bool TryGetPinnedObject(ulong addr, out object? o)
{
lock (_lock)
{
Expand Down Expand Up @@ -118,15 +118,16 @@ public bool Unpin(ulong objAddress)
.Select(kvp => kvp.Key)
.ToArray();

// Making sure that adress was even in the dictionary.
// Making sure that address was even in the dictionary.
// Otherwise, we don't need to re-pin all objects.
Logger.Debug($"[{nameof(FrozenObjectsCollection)}] Unpinning another object. New Num Pinned: {objs.Length}");
// Logger.Debug($"[{nameof(FrozenObjectsCollection)}] Unpinning another object. New Num Pinned: {objs.Length}");
if (objs.Length == _frozenObjects.Count)
return false;

// Re-pin all objects
PinInternal(objs);

Logger.Debug($"[{nameof(FrozenObjectsCollection)}] Unpinned another object. Final Num Pinned: {_frozenObjects.Count}");
// Logger.Debug($"[{nameof(FrozenObjectsCollection)}] Unpinned another object. Final Num Pinned: {_frozenObjects.Count}");
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using System.Runtime.InteropServices;


namespace ScubaDiver;
namespace MTGOSDK.Core.Reflection.Emit;

/// <summary>
/// This class is used to make arbitrary objects "Pinnable" in the .NET
Expand Down
25 changes: 25 additions & 0 deletions MTGOSDK/src/Core/Reflection/EventWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/** @file
Copyright (c) 2024, Cory Bennett. All rights reserved.
SPDX-License-Identifier: Apache-2.0
**/

using System;


namespace MTGOSDK.Core.Reflection;

/// <summary>
/// Wraps a generic method to be used as an event handler for subscription.
/// </summary>
/// <typeparam name="T">The type of the event arguments.</typeparam>
/// <param name="handler">The method to be wrapped.</param>
public class EventWrapper<T>(EventHandler handler) where T : EventArgs
{
/// <summary>
/// The handler method to be invoked when the event is raised.
/// </summary>
public void Handle(object sender, T args)
{
handler.Invoke(sender, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@
using Microsoft.Diagnostics.Runtime;


namespace ScubaDiver;


public struct TypeDefToMethod
{
public ulong MethodTable { get; set; }
public int Token { get; set; }
}
namespace MTGOSDK.Core.Reflection.Snapshot;

public static class ClrExt
{
public struct TypeDefToMethod
{
public ulong MethodTable { get; set; }
public int Token { get; set; }
}

public static byte[] ToByteArray(this ClrArray arr)
{
try
Expand Down
Loading

0 comments on commit fe14836

Please sign in to comment.