Skip to content

Commit

Permalink
Enhancement: support for platform-specific patterns for procedure ent…
Browse files Browse the repository at this point in the history
…ries.
  • Loading branch information
uxmal committed Apr 7, 2022
1 parent 432fc95 commit db5d3c7
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 77 deletions.
6 changes: 4 additions & 2 deletions src/Core/Configuration/PlatformArchitectureDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ public PlatformArchitectureDefinition()
{
this.TrashedRegisters = new List<string>();
this.TypeLibraries = new List<TypeLibraryDefinition>();
this.ProcedurePrologs = new List<MaskedPattern>();
}

public string? Name { get; set; }
public List<string> TrashedRegisters { get; internal set; }
public List<TypeLibraryDefinition> TypeLibraries { get; internal set; }
public List<string> TrashedRegisters { get; set; }
public List<TypeLibraryDefinition> TypeLibraries { get; set; }
public List<MaskedPattern> ProcedurePrologs { get; set; }
}
}
64 changes: 1 addition & 63 deletions src/Core/Configuration/PlatformDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private PlatformHeuristics LoadHeuristics(PlatformHeuristics_v1? heuristics)
else
{
prologs = heuristics.ProcedurePrologs
.Select(p => LoadMaskedPattern(p)!)
.Select(p => MaskedPattern.Load(p.Bytes, p.Mask)!)
.Where(p => p != null && p.Bytes != null)
.ToArray();
}
Expand All @@ -125,68 +125,6 @@ private PlatformHeuristics LoadHeuristics(PlatformHeuristics_v1? heuristics)
};
}

public MaskedPattern? LoadMaskedPattern(BytePattern_v1 sPattern)
{
if (sPattern.Bytes == null)
return null;
if (sPattern.Mask == null)
{
var bytes = new List<byte>();
var mask = new List<byte>();
int shift = 4;
int bb = 0;
int mm = 0;
for (int i = 0; i < sPattern.Bytes.Length; ++i)
{
char c = sPattern.Bytes[i];
if (BytePattern.TryParseHexDigit(c, out byte b))
{
bb |= (b << shift);
mm |= (0x0F << shift);
shift -= 4;
if (shift < 0)
{
bytes.Add((byte)bb);
mask.Add((byte)mm);
shift = 4;
bb = mm = 0;
}
}
else if (c == '?' || c == '.')
{
shift -= 4;
if (shift < 0)
{
bytes.Add((byte)bb);
mask.Add((byte)mm);
shift = 4;
bb = mm = 0;
}
}
}
Debug.Assert(bytes.Count == mask.Count);
if (bytes.Count == 0)
return null;
return new MaskedPattern
{
Bytes = bytes.ToArray(),
Mask = mask.ToArray()
};
}
else
{
var bytes = BytePattern.FromHexBytes(sPattern.Bytes);
var mask = BytePattern.FromHexBytes(sPattern.Mask);
if (bytes.Length == 0)
return null;
return new MaskedPattern
{
Bytes = bytes.ToArray(),
Mask = mask.ToArray()
};
}
}

private Dictionary<Address, ExternalProcedure> LoadPlatformProcedures(Platform platform)
{
if (platform.MemoryMap != null && platform.MemoryMap.Segments != null)
Expand Down
17 changes: 15 additions & 2 deletions src/Core/Configuration/RekoConfigurationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,15 +207,28 @@ private TypeLibraryDefinition LoadTypeLibraryReference(TypeLibraryReference_v1 t
private PlatformArchitectureDefinition LoadPlatformArchitecture(PlatformArchitecture_v1 spa)
{
var sTrashedRegs = spa.TrashedRegisters ?? "";
var sLibraries = spa.TypeLibraries ?? new TypeLibraryReference_v1[0];
List<MaskedPattern> prologs;
if (spa.ProcedurePrologs is null)
{
prologs = new();
}
else
{
prologs = spa.ProcedurePrologs
.Select(p => MaskedPattern.Load(p.Bytes, p.Mask)!)
.Where(p => p != null && p.Bytes != null)
.ToList();
}

return new PlatformArchitectureDefinition
{
Name = spa.Name,
TrashedRegisters = sTrashedRegs
.Split(',')
.Select(s => s.Trim())
.ToList(),
TypeLibraries = LoadCollection(sLibraries, LoadTypeLibraryReference)
TypeLibraries = LoadCollection(spa.TypeLibraries, LoadTypeLibraryReference),
ProcedurePrologs = prologs
};
}

Expand Down
5 changes: 5 additions & 0 deletions src/Core/Configuration/RekoConfiguration_v1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@ public class PlatformArchitecture_v1
[XmlArray("TypeLibraries")]
[XmlArrayItem("TypeLibrary")]
public TypeLibraryReference_v1[]? TypeLibraries;

[XmlArray("ProcedurePrologs")]
[XmlArrayItem("Pattern")]
public BytePattern_v1[]? ProcedurePrologs;

}

/// <summary>
Expand Down
63 changes: 63 additions & 0 deletions src/Core/PlatformHeuristics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

Expand All @@ -34,5 +35,67 @@ public class MaskedPattern
{
public byte[]? Bytes;
public byte[]? Mask;

public static MaskedPattern? Load(string? sBytes, string? sMask)
{
if (sBytes == null)
return null;
if (sMask == null)
{
var bytes = new List<byte>();
var mask = new List<byte>();
int shift = 4;
int bb = 0;
int mm = 0;
for (int i = 0; i < sBytes.Length; ++i)
{
char c = sBytes[i];
if (BytePattern.TryParseHexDigit(c, out byte b))
{
bb |= (b << shift);
mm |= (0x0F << shift);
shift -= 4;
if (shift < 0)
{
bytes.Add((byte) bb);
mask.Add((byte) mm);
shift = 4;
bb = mm = 0;
}
}
else if (c == '?' || c == '.')
{
shift -= 4;
if (shift < 0)
{
bytes.Add((byte) bb);
mask.Add((byte) mm);
shift = 4;
bb = mm = 0;
}
}
}
Debug.Assert(bytes.Count == mask.Count);
if (bytes.Count == 0)
return null;
return new MaskedPattern
{
Bytes = bytes.ToArray(),
Mask = mask.ToArray()
};
}
else
{
var bytes = BytePattern.FromHexBytes(sBytes);
var mask = BytePattern.FromHexBytes(sMask);
if (bytes.Length == 0)
return null;
return new MaskedPattern
{
Bytes = bytes.ToArray(),
Mask = mask.ToArray()
};
}
}
}
}
6 changes: 6 additions & 0 deletions src/Drivers/reko.config
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@
<Architectures>
<Architecture name="x86-protected-32">
<TrashedRegisters>eax,ecx,edx</TrashedRegisters>
<ProcedurePrologs>
<Pattern>
<Bytes>55 8B EC</Bytes>
<Mask>FF FF FF</Mask>
</Pattern>
</ProcedurePrologs>
</Architecture>
<Architecture name="x86-protected-64">
<TrashedRegisters>rax,rcx,rdx,rsi,rdi,r8,r9,r10,r11</TrashedRegisters>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#region License
#region License
/*
* Copyright (C) 1999-2022 John Källén.
*
Expand Down Expand Up @@ -40,7 +40,7 @@ public void Oee_LoadPrologPattern_WithMask()
Mask = "FF C0 0F",
};
var element = new PlatformDefinition();
var pattern = element.LoadMaskedPattern(sPattern);
var pattern = MaskedPattern.Load(sPattern.Bytes, sPattern.Mask);
Assert.AreEqual(new byte[] { 0x55, 0x32, 0x12 }, pattern.Bytes);
Assert.AreEqual(new byte[] { 0xFF, 0xC0, 0x0F }, pattern.Mask);
}
Expand All @@ -53,7 +53,7 @@ public void Oee_LoadPrologPattern_WithoutMask()
Bytes = "55 3? ?2",
};
var element = new PlatformDefinition();
var pattern = element.LoadMaskedPattern(sPattern);
var pattern = MaskedPattern.Load(sPattern.Bytes, sPattern.Mask);
Assert.AreEqual(new byte[] { 0x55, 0x30, 0x02 }, pattern.Bytes);
Assert.AreEqual(new byte[] { 0xFF, 0xF0, 0x0F }, pattern.Mask);
}
Expand Down
22 changes: 15 additions & 7 deletions src/UnitTests/Core/Configuration/RekoConfigurationServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,20 @@ public void Rcfg_LoadOperatingEnvironment()
new PlatformArchitecture_v1
{
Name="testCPU",
TypeLibraries = new[]
{
new TypeLibraryReference_v1
{
Name = "lp32.xml",
}
}
TypeLibraries = new[]
{
new TypeLibraryReference_v1
{
Name = "lp32.xml",
}
},
ProcedurePrologs = new[]
{
new BytePattern_v1
{
Bytes = "55 8B EC"
}
}
}
}
}
Expand All @@ -107,6 +114,7 @@ public void Rcfg_LoadOperatingEnvironment()
var archs = env.Architectures;
Assert.AreEqual(1, archs.Count);
Assert.AreEqual("lp32.xml", archs[0].TypeLibraries[0].Name);
Assert.AreEqual(0xEC, archs[0].ProcedurePrologs[0].Bytes[2]);
}

[Test]
Expand Down

0 comments on commit db5d3c7

Please sign in to comment.