mirror of
https://github.com/AdvDebug/Brovan
synced 2026-08-09 11:57:17 +00:00
Refactor struct serializer generator with explicit opt-in
Changes struct serializer generator to require explicit [GenerateStructSerializer] attribute instead of auto-detecting fields with [EmulatedInline]/[EmulatedPointer]. Major internal refactoring includes: - Replace implicit detection with explicit opt-in via marker attribute - Refactor field processing into FieldSlot-based recursive walking for better nested struct/array support - Add diagnostic reporting for unsupported field types and nesting depth limits
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ using Brovan.Core.Emulation.OS.Linux.Files;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Linux
|
||||
{
|
||||
[GenerateStructSerializer]
|
||||
public struct Utsname
|
||||
{
|
||||
[EmulatedInline(65, Ascii = true)]
|
||||
@@ -26,6 +27,7 @@ namespace Brovan.Core.Emulation.OS.Linux
|
||||
}
|
||||
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct LinuxStat32
|
||||
{
|
||||
@@ -90,6 +92,7 @@ namespace Brovan.Core.Emulation.OS.Linux
|
||||
public uint __unused5;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct LinuxStatCompat64
|
||||
{
|
||||
@@ -162,6 +165,7 @@ namespace Brovan.Core.Emulation.OS.Linux
|
||||
public long tv_nsec;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct LinuxStat64
|
||||
{
|
||||
|
||||
@@ -25,6 +25,16 @@ namespace Brovan.Core.Emulation.OS
|
||||
public EmulatedInlineAttribute(int Size) => this.Size = Size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opts a struct into <see cref="Brovan.Generators.StructSerializerGenerator"/>, which emits
|
||||
/// reflection-free WriteStructDirect_/ParseStructDirect_/GetStructSizeDirect_ methods on
|
||||
/// <see cref="StructSerializer"/> for it.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Struct)]
|
||||
public sealed class GenerateStructSerializerAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public enum WriteStructError
|
||||
{
|
||||
None, NullDestination, DestinationNotMapped, PointerAllocationFailed,
|
||||
@@ -186,6 +196,31 @@ namespace Brovan.Core.Emulation.OS
|
||||
return Cache[T] = new TypeDesc(T);
|
||||
}
|
||||
|
||||
// --- Generated-serializer dispatch ---
|
||||
|
||||
internal delegate bool ParseStructAddrDelegate<T>(BinaryEmulator Emulator, ulong Address, out T Value);
|
||||
internal delegate bool ParseStructBytesDelegate<T>(BinaryEmulator Emulator, byte[] Raw, out T Value);
|
||||
|
||||
private static readonly Dictionary<Type, Delegate> DirectWrite = new();
|
||||
private static readonly Dictionary<Type, Delegate> DirectParseAddr = new();
|
||||
private static readonly Dictionary<Type, Delegate> DirectParseBytes = new();
|
||||
private static readonly Dictionary<Type, Delegate> DirectSizeBool = new();
|
||||
private static readonly Dictionary<Type, Delegate> DirectSizeEmulator = new();
|
||||
|
||||
internal static void RegisterDirect<T>(
|
||||
Func<BinaryEmulator, ulong, T, WriteStructResult> Write,
|
||||
ParseStructAddrDelegate<T> ParseAddr,
|
||||
ParseStructBytesDelegate<T> ParseBytes,
|
||||
Func<bool, int> SizeBool,
|
||||
Func<BinaryEmulator, int> SizeEmulator) where T : struct
|
||||
{
|
||||
DirectWrite[typeof(T)] = Write;
|
||||
DirectParseAddr[typeof(T)] = ParseAddr;
|
||||
DirectParseBytes[typeof(T)] = ParseBytes;
|
||||
DirectSizeBool[typeof(T)] = SizeBool;
|
||||
DirectSizeEmulator[typeof(T)] = SizeEmulator;
|
||||
}
|
||||
|
||||
// --- Public API ---
|
||||
|
||||
/// <summary>
|
||||
@@ -196,6 +231,9 @@ namespace Brovan.Core.Emulation.OS
|
||||
/// <returns>return the size.</returns>
|
||||
public static uint GetStructSize<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] T>(BinaryEmulator Emulator) where T : struct
|
||||
{
|
||||
if (DirectSizeEmulator.TryGetValue(typeof(T), out Delegate Fast))
|
||||
return (uint)((Func<BinaryEmulator, int>)Fast)(Emulator);
|
||||
|
||||
bool Is64 = Emulator._binary.Architecture == BinaryArchitecture.x64;
|
||||
return (uint)GetStructSize(typeof(T), Is64);
|
||||
}
|
||||
@@ -208,6 +246,9 @@ namespace Brovan.Core.Emulation.OS
|
||||
/// <returns>return the size.</returns>
|
||||
public static int GetStructSize<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] T>(bool Is64) where T : struct
|
||||
{
|
||||
if (DirectSizeBool.TryGetValue(typeof(T), out Delegate Fast))
|
||||
return ((Func<bool, int>)Fast)(Is64);
|
||||
|
||||
return GetStructSize(typeof(T), Is64);
|
||||
}
|
||||
|
||||
@@ -232,6 +273,9 @@ namespace Brovan.Core.Emulation.OS
|
||||
/// <returns>Returns <see cref="WriteStructResult.Ok"/> on success, otherwise a failure result describing the error.</returns>
|
||||
public static WriteStructResult WriteStruct<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] T>(BinaryEmulator Emulator, ulong Address, T Value) where T : struct
|
||||
{
|
||||
if (DirectWrite.TryGetValue(typeof(T), out Delegate Fast))
|
||||
return ((Func<BinaryEmulator, ulong, T, WriteStructResult>)Fast)(Emulator, Address, Value);
|
||||
|
||||
if (Address == 0)
|
||||
return WriteStructResult.Fail(WriteStructError.NullDestination, $"Destination address is NULL for {typeof(T).Name}");
|
||||
|
||||
@@ -293,6 +337,9 @@ namespace Brovan.Core.Emulation.OS
|
||||
/// <returns>Returns true if successful, otherwise false.</returns>
|
||||
public static bool ParseStruct<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] T>(BinaryEmulator Emulator, ulong Address, out T Value) where T : struct
|
||||
{
|
||||
if (DirectParseAddr.TryGetValue(typeof(T), out Delegate Fast))
|
||||
return ((ParseStructAddrDelegate<T>)Fast)(Emulator, Address, out Value);
|
||||
|
||||
Value = default;
|
||||
if (Address == 0) return false;
|
||||
|
||||
@@ -342,6 +389,9 @@ namespace Brovan.Core.Emulation.OS
|
||||
/// </remarks>
|
||||
public static bool ParseStruct<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] T>(BinaryEmulator Emulator, byte[] Data, out T Value) where T : struct
|
||||
{
|
||||
if (DirectParseBytes.TryGetValue(typeof(T), out Delegate Fast))
|
||||
return ((ParseStructBytesDelegate<T>)Fast)(Emulator, Data, out Value);
|
||||
|
||||
Value = default;
|
||||
|
||||
bool Is64 = Emulator._binary.Architecture == BinaryArchitecture.x64;
|
||||
|
||||
@@ -16,8 +16,9 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
private const uint IoctlConDrvGetDisplayMode = 0x00500027;
|
||||
private const uint IoctlConDrvSetDisplayMode = 0x0050002B;
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x30)]
|
||||
private struct ConsoleApiMsgHeader
|
||||
internal struct ConsoleApiMsgHeader
|
||||
{
|
||||
[FieldOffset(0x28)] public uint ApiNumber;
|
||||
[FieldOffset(0x2C)] public uint ApiDescriptorSize;
|
||||
|
||||
@@ -8,7 +8,8 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
internal class NtConnectPort : IWinSyscall
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct PORT_VIEW64
|
||||
[GenerateStructSerializer]
|
||||
internal struct PORT_VIEW64
|
||||
{
|
||||
public uint Length;
|
||||
public uint Padding0;
|
||||
@@ -20,8 +21,9 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public ulong ViewRemoteBase;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct REMOTE_PORT_VIEW64
|
||||
internal struct REMOTE_PORT_VIEW64
|
||||
{
|
||||
public uint Length;
|
||||
public uint Padding0;
|
||||
|
||||
@@ -177,7 +177,8 @@ namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 80)]
|
||||
private struct WNDCLASSEXW64
|
||||
[GenerateStructSerializer]
|
||||
internal struct WNDCLASSEXW64
|
||||
{
|
||||
[FieldOffset(0)] public uint cbSize;
|
||||
[FieldOffset(4)] public uint style;
|
||||
@@ -193,8 +194,9 @@ namespace Brovan.Core.Emulation.OS.Windows.Win32k
|
||||
[FieldOffset(72)] public ulong hIconSm;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit, Size = 24)]
|
||||
private struct CLSMENUNAME64
|
||||
internal struct CLSMENUNAME64
|
||||
{
|
||||
[FieldOffset(0)] public ulong pszClientAnsiMenuName;
|
||||
[FieldOffset(8)] public ulong pwszClientUnicodeMenuName;
|
||||
|
||||
@@ -9,6 +9,7 @@ using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows
|
||||
{
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct UNICODE_STRING
|
||||
{
|
||||
@@ -22,6 +23,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public uint Buffer;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct UNICODE_STRING64
|
||||
{
|
||||
@@ -35,6 +37,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public ulong Buffer;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit, Size = 48)]
|
||||
public struct OBJECT_ATTRIBUTES64
|
||||
{
|
||||
@@ -57,6 +60,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public ulong SecurityQualityOfService;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MEMORY_REGION_INFORMATION
|
||||
{
|
||||
@@ -69,6 +73,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public ulong NodePreference;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MEMORY_IMAGE_EXTENSION_INFORMATION
|
||||
{
|
||||
@@ -78,6 +83,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public ulong ExtensionSize;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MEMORY_WORKING_SET_EX_INFORMATION
|
||||
{
|
||||
@@ -154,6 +160,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public ulong Rip;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MEMORY_BASIC_INFORMATION
|
||||
{
|
||||
@@ -169,6 +176,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public uint Reserved2; // tail padding to 48 bytes
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MEMORY_IMAGE_INFORMATION
|
||||
{
|
||||
@@ -217,6 +225,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
MutantOwnerInformation = 1
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct MUTANT_BASIC_INFORMATION
|
||||
{
|
||||
@@ -231,6 +240,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
SemaphoreBasicInformation = 0
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct SEMAPHORE_BASIC_INFORMATION
|
||||
{
|
||||
@@ -238,6 +248,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public int MaximumCount;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct OBJECT_BASIC_INFORMATION_DATA
|
||||
{
|
||||
@@ -256,6 +267,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public long CreationTime;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct OBJECT_TYPE_INFORMATION64
|
||||
{
|
||||
@@ -284,6 +296,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public uint DefaultNonPagedPoolCharge;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct OBJECT_TYPE_INFORMATION32
|
||||
{
|
||||
@@ -312,6 +325,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public uint DefaultNonPagedPoolCharge;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Explicit, Size = 16)]
|
||||
public struct LARGE_STRING64
|
||||
{
|
||||
@@ -325,6 +339,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public ulong Buffer;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
@@ -334,6 +349,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public int Bottom;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SYSTEM_BATTERY_STATE
|
||||
{
|
||||
@@ -361,6 +377,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
public uint Capacity;
|
||||
}
|
||||
|
||||
[GenerateStructSerializer]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SYSTEM_POWER_CAPABILITIES
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user