Skip to content

Commit ead9f20

Browse files
committed
Removed methods which read structs from memory.
This change is needed to add support for little/big endian support. Benchmarks have shown that the ReadObject method is faster for structs with more than six 4 byte fields. Only the matrix nodes have such big structures so this change speeds up all smaller reads.
1 parent 726b6ab commit ead9f20

15 files changed

+85
-368
lines changed

ReClass.NET/Memory/IRemoteMemoryReader.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Text;
33

44
namespace ReClassNET.Memory
@@ -23,12 +23,6 @@ public interface IRemoteMemoryReader
2323
/// <returns>An array of bytes.</returns>
2424
byte[] ReadRemoteMemory(IntPtr address, int size);
2525

26-
/// <summary>Reads the object from the address in the remote process.</summary>
27-
/// <typeparam name="T">Type of the value to read.</typeparam>
28-
/// <param name="address">The address to read from.</param>
29-
/// <returns>The remote object.</returns>
30-
T ReadRemoteObject<T>(IntPtr address) where T : struct;
31-
3226
/// <summary>Reads a <see cref="sbyte"/> from the address in the remote process.</summary>
3327
/// <param name="address">The address to read from.</param>
3428
/// <returns>The data read as <see cref="sbyte"/> or 0 if the read fails.</returns>

ReClass.NET/Memory/MemoryBuffer.cs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -133,23 +133,6 @@ public void ReadBytes(int offset, byte[] buffer)
133133
Array.Copy(data, offset, buffer, 0, buffer.Length);
134134
}
135135

136-
public T ReadObject<T>(int offset) where T : struct
137-
{
138-
Contract.Requires(offset >= 0);
139-
140-
offset = Offset + offset;
141-
if (offset + Marshal.SizeOf(typeof(T)) > data.Length)
142-
{
143-
return default;
144-
}
145-
146-
var handle = GCHandle.Alloc(data, GCHandleType.Pinned);
147-
var obj = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject() + offset);
148-
handle.Free();
149-
150-
return obj;
151-
}
152-
153136
#region Read Primitive Types
154137

155138
/// <summary>Reads a <see cref="sbyte"/> from the specific offset.</summary>

ReClass.NET/Memory/NodeDissector.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics.Contracts;
44
using System.Linq;
@@ -41,8 +41,15 @@ public static bool GuessNode(BaseHexNode node, IProcessReader reader, MemoryBuff
4141
return false;
4242
}
4343

44-
var data64 = memory.ReadObject<UInt64FloatDoubleData>(offset);
45-
var data32 = memory.ReadObject<UInt32FloatData>(offset);
44+
var data64 = new UInt64FloatDoubleData
45+
{
46+
Raw1 = memory.ReadInt32(offset),
47+
Raw2 = memory.ReadInt32(offset + sizeof(int))
48+
}; ;
49+
var data32 = new UInt32FloatData
50+
{
51+
Raw = memory.ReadInt32(offset)
52+
};
4653

4754
var raw = memory.ReadBytes(offset, node.MemorySize);
4855
if (raw.InterpretAsSingleByteCharacter().IsLikelyPrintableData())
@@ -135,10 +142,9 @@ private static bool GuessPointerNode(IntPtr address, IProcessReader process, out
135142
if (section.Category == SectionCategory.DATA || section.Category == SectionCategory.HEAP) // If the section contains data, it is at least a pointer to a class or something.
136143
{
137144
// Check if it is a vtable. Check if the first 3 values are pointers to a code section.
138-
var possibleVmt = process.ReadRemoteObject<ThreePointersData>(address);
139-
if (process.GetSectionToPointer(possibleVmt.Pointer1)?.Category == SectionCategory.CODE
140-
&& process.GetSectionToPointer(possibleVmt.Pointer2)?.Category == SectionCategory.CODE
141-
&& process.GetSectionToPointer(possibleVmt.Pointer3)?.Category == SectionCategory.CODE)
145+
if (process.GetSectionToPointer(process.ReadRemoteIntPtr(address))?.Category == SectionCategory.CODE
146+
&& process.GetSectionToPointer(process.ReadRemoteIntPtr(address + IntPtr.Size))?.Category == SectionCategory.CODE
147+
&& process.GetSectionToPointer(process.ReadRemoteIntPtr(address + 2 * IntPtr.Size))?.Category == SectionCategory.CODE)
142148
{
143149
node = new VirtualMethodTableNode();
144150

ReClass.NET/Memory/RemoteProcess.cs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics.Contracts;
44
using System.Linq;
@@ -185,17 +185,6 @@ public byte[] ReadRemoteMemory(IntPtr address, int size)
185185
return data;
186186
}
187187

188-
public T ReadRemoteObject<T>(IntPtr address) where T : struct
189-
{
190-
var data = ReadRemoteMemory(address, Marshal.SizeOf<T>());
191-
192-
var gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
193-
var obj = (T)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof(T));
194-
gcHandle.Free();
195-
196-
return obj;
197-
}
198-
199188
#region Read Remote Primitive Types
200189

201190
public sbyte ReadRemoteInt8(IntPtr address)

ReClass.NET/Memory/UnionDataType.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Runtime.InteropServices;
33

44
namespace ReClassNET.Memory
@@ -26,6 +26,9 @@ public struct UInt16Data
2626
[StructLayout(LayoutKind.Explicit)]
2727
public struct UInt32FloatData
2828
{
29+
[FieldOffset(0)]
30+
public int Raw;
31+
2932
[FieldOffset(0)]
3033
public int IntValue;
3134

@@ -43,6 +46,12 @@ public struct UInt32FloatData
4346
[StructLayout(LayoutKind.Explicit)]
4447
public struct UInt64FloatDoubleData
4548
{
49+
[FieldOffset(0)]
50+
public int Raw1;
51+
52+
[FieldOffset(4)]
53+
public int Raw2;
54+
4655
[FieldOffset(0)]
4756
public long LongValue;
4857

@@ -69,12 +78,4 @@ public struct UInt64FloatDoubleData
6978
[FieldOffset(0)]
7079
public double DoubleValue;
7180
}
72-
73-
[StructLayout(LayoutKind.Sequential)]
74-
public struct ThreePointersData
75-
{
76-
public IntPtr Pointer1;
77-
public IntPtr Pointer2;
78-
public IntPtr Pointer3;
79-
}
8081
}

ReClass.NET/Nodes/BaseMatrixNode.cs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Diagnostics.Contracts;
23
using System.Drawing;
34
using ReClassNET.Controls;
@@ -17,11 +18,10 @@ protected BaseMatrixNode()
1718

1819
protected delegate void DrawMatrixValues(int x, ref int maxX, ref int y);
1920

20-
protected Size DrawMatrixType(DrawContext context, int x, int y, string type, DrawMatrixValues drawValues)
21+
protected Size DrawMatrixType(DrawContext context, int x, int y, string type, int rows, int columns)
2122
{
2223
Contract.Requires(context != null);
2324
Contract.Requires(type != null);
24-
Contract.Requires(drawValues != null);
2525

2626
if (IsHidden && !IsWrapped)
2727
{
@@ -58,18 +58,36 @@ protected Size DrawMatrixType(DrawContext context, int x, int y, string type, Dr
5858

5959
if (LevelsOpen[context.Level])
6060
{
61-
drawValues(tx, ref x, ref y);
61+
var index = 0;
62+
for (var row = 0; row < rows; ++row)
63+
{
64+
y += context.Font.Height;
65+
var x2 = tx;
66+
67+
x2 = AddText(context, x2, y, context.Settings.NameColor, HotSpot.NoneId, "|");
68+
69+
for (var column = 0; column < columns; ++column)
70+
{
71+
var value = context.Memory.ReadFloat(Offset + index * sizeof(float));
72+
x2 = AddText(context, x2, y, context.Settings.ValueColor, index, $"{value,14:0.000}");
73+
74+
index++;
75+
}
76+
77+
x2 = AddText(context, x2, y, context.Settings.NameColor, HotSpot.NoneId, "|");
78+
79+
x = Math.Max(x2, x);
80+
}
6281
}
6382

6483
return new Size(x - origX, y - origY + context.Font.Height);
6584
}
6685

6786
protected delegate void DrawVectorValues(ref int x, ref int y);
68-
protected Size DrawVectorType(DrawContext context, int x, int y, string type, DrawVectorValues drawValues)
87+
protected Size DrawVectorType(DrawContext context, int x, int y, string type, int columns)
6988
{
7089
Contract.Requires(context != null);
7190
Contract.Requires(type != null);
72-
Contract.Requires(drawValues != null);
7391

7492
if (IsHidden && !IsWrapped)
7593
{
@@ -97,7 +115,19 @@ protected Size DrawVectorType(DrawContext context, int x, int y, string type, Dr
97115

98116
if (LevelsOpen[context.Level])
99117
{
100-
drawValues(ref x, ref y);
118+
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, "(");
119+
for (var column = 0; column < columns; ++column)
120+
{
121+
var value = context.Memory.ReadFloat(Offset + column * sizeof(float));
122+
123+
x = AddText(context, x, y, context.Settings.ValueColor, column, $"{value:0.000}");
124+
125+
if (column < columns - 1)
126+
{
127+
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ",");
128+
}
129+
}
130+
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ")");
101131
}
102132

103133
x += context.Font.Width;

ReClass.NET/Nodes/Hex16Node.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
1717

1818
public override string GetToolTipText(HotSpot spot)
1919
{
20-
var value = spot.Memory.ReadObject<UInt16Data>(Offset);
20+
var value = new UInt16Data { ShortValue = spot.Memory.ReadInt16(Offset) };
2121

2222
return $"Int16: {value.ShortValue}\nUInt16: 0x{value.UShortValue:X04}";
2323
}

ReClass.NET/Nodes/Hex32Node.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
1818

1919
public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
2020
{
21-
var value = spot.Memory.ReadObject<UInt32FloatData>(Offset);
21+
var value = ReadFromBuffer(spot.Memory, Offset);
2222

2323
address = value.IntPtr;
2424

@@ -27,7 +27,7 @@ public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
2727

2828
public override string GetToolTipText(HotSpot spot)
2929
{
30-
var value = spot.Memory.ReadObject<UInt32FloatData>(Offset);
30+
var value = ReadFromBuffer(spot.Memory, Offset);
3131

3232
return $"Int32: {value.IntValue}\nUInt32: 0x{value.UIntValue:X08}\nFloat: {value.FloatValue:0.000}";
3333
}
@@ -46,11 +46,16 @@ protected override int AddComment(DrawContext context, int x, int y)
4646
{
4747
x = base.AddComment(context, x, y);
4848

49-
var value = context.Memory.ReadObject<UInt32FloatData>(Offset);
49+
var value = ReadFromBuffer(context.Memory, Offset);
5050

5151
x = AddComment(context, x, y, value.FloatValue, value.IntPtr, value.UIntPtr);
5252

5353
return x;
5454
}
55+
56+
private static UInt32FloatData ReadFromBuffer(MemoryBuffer memory, int offset) => new UInt32FloatData
57+
{
58+
Raw = memory.ReadInt32(offset)
59+
};
5560
}
5661
}

ReClass.NET/Nodes/Hex64Node.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
1818

1919
public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
2020
{
21-
var value = spot.Memory.ReadObject<UInt64FloatDoubleData>(Offset);
21+
var value = ReadFromBuffer(spot.Memory, Offset);
2222

2323
address = value.IntPtr;
2424

@@ -27,7 +27,7 @@ public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
2727

2828
public override string GetToolTipText(HotSpot spot)
2929
{
30-
var value = spot.Memory.ReadObject<UInt64FloatDoubleData>(Offset);
30+
var value = ReadFromBuffer(spot.Memory, Offset);
3131

3232
return $"Int64: {value.LongValue}\nUInt64: 0x{value.ULongValue:X016}\nFloat: {value.FloatValue:0.000}\nDouble: {value.DoubleValue:0.000}";
3333
}
@@ -46,11 +46,17 @@ protected override int AddComment(DrawContext context, int x, int y)
4646
{
4747
x = base.AddComment(context, x, y);
4848

49-
var value = context.Memory.ReadObject<UInt64FloatDoubleData>(Offset);
49+
var value = ReadFromBuffer(context.Memory, Offset);
5050

5151
x = AddComment(context, x, y, value.FloatValue, value.IntPtr, value.UIntPtr);
5252

5353
return x;
5454
}
55+
56+
private static UInt64FloatDoubleData ReadFromBuffer(MemoryBuffer memory, int offset) => new UInt64FloatDoubleData
57+
{
58+
Raw1 = memory.ReadInt32(offset),
59+
Raw2 = memory.ReadInt32(offset + sizeof(int))
60+
};
5561
}
5662
}

ReClass.NET/Nodes/Matrix3x3Node.cs

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,11 @@
1-
using System;
21
using System.Drawing;
3-
using System.Runtime.InteropServices;
42
using ReClassNET.Controls;
53
using ReClassNET.UI;
64

75
namespace ReClassNET.Nodes
86
{
97
public class Matrix3x3Node : BaseMatrixNode
108
{
11-
[StructLayout(LayoutKind.Explicit)]
12-
private readonly struct Matrix3x3Data
13-
{
14-
[FieldOffset(0)]
15-
public readonly float _11;
16-
[FieldOffset(4)]
17-
public readonly float _12;
18-
[FieldOffset(8)]
19-
public readonly float _13;
20-
[FieldOffset(12)]
21-
public readonly float _21;
22-
[FieldOffset(16)]
23-
public readonly float _22;
24-
[FieldOffset(20)]
25-
public readonly float _23;
26-
[FieldOffset(24)]
27-
public readonly float _31;
28-
[FieldOffset(28)]
29-
public readonly float _32;
30-
[FieldOffset(32)]
31-
public readonly float _33;
32-
}
33-
349
public override int ValueTypeSize => sizeof(float);
3510

3611
public override int MemorySize => 9 * ValueTypeSize;
@@ -43,43 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
4318

4419
public override Size Draw(DrawContext context, int x2, int y2)
4520
{
46-
return DrawMatrixType(context, x2, y2, "Matrix (3x3)", (int defaultX, ref int maxX, ref int y) =>
47-
{
48-
var value = context.Memory.ReadObject<Matrix3x3Data>(Offset);
49-
50-
y += context.Font.Height;
51-
var x = defaultX;
52-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, "|");
53-
x = AddText(context, x, y, context.Settings.ValueColor, 0, $"{value._11,14:0.000}");
54-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ",");
55-
x = AddText(context, x, y, context.Settings.ValueColor, 1, $"{value._12,14:0.000}");
56-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ",");
57-
x = AddText(context, x, y, context.Settings.ValueColor, 2, $"{value._13,14:0.000}");
58-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, "|");
59-
maxX = Math.Max(x, maxX);
60-
61-
y += context.Font.Height;
62-
x = defaultX;
63-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, "|");
64-
x = AddText(context, x, y, context.Settings.ValueColor, 3, $"{value._21,14:0.000}");
65-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ",");
66-
x = AddText(context, x, y, context.Settings.ValueColor, 4, $"{value._22,14:0.000}");
67-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ",");
68-
x = AddText(context, x, y, context.Settings.ValueColor, 5, $"{value._23,14:0.000}");
69-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, "|");
70-
maxX = Math.Max(x, maxX);
71-
72-
y += context.Font.Height;
73-
x = defaultX;
74-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, "|");
75-
x = AddText(context, x, y, context.Settings.ValueColor, 6, $"{value._31,14:0.000}");
76-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ",");
77-
x = AddText(context, x, y, context.Settings.ValueColor, 7, $"{value._32,14:0.000}");
78-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, ",");
79-
x = AddText(context, x, y, context.Settings.ValueColor, 8, $"{value._33,14:0.000}");
80-
x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NoneId, "|");
81-
maxX = Math.Max(x, maxX);
82-
});
21+
return DrawMatrixType(context, x2, y2, "Matrix (3x3)", 3, 3);
8322
}
8423

8524
protected override int CalculateValuesHeight(DrawContext context)

0 commit comments

Comments
 (0)