From 47802dcbb12780357b3ad11f8be4fb4fb4963128 Mon Sep 17 00:00:00 2001 From: Kevin Ferrare Date: Fri, 19 Jan 2024 01:44:51 +0100 Subject: [PATCH] Address of CfgNodes is a segmented address and not a physical address to take into account the differences in execution results when an instruction at the same physical address is executed with different segmented addresses --- .../CPU/CfgCpu/ControlFlowGraph/CfgNode.cs | 8 +- .../CPU/CfgCpu/ControlFlowGraph/ICfgNode.cs | 5 +- .../CPU/CfgCpu/Feeder/CfgNodeFeeder.cs | 2 +- .../CPU/CfgCpu/Feeder/CurrentInstructions.cs | 28 +- .../CPU/CfgCpu/Feeder/InstructionsFeeder.cs | 2 +- .../CfgCpu/Feeder/MemoryInstructionMatcher.cs | 2 +- .../CPU/CfgCpu/Feeder/PreviousInstructions.cs | 18 +- .../ExecutorCfgNodeVisitor.cs | 4 +- .../Emulator/CPU/CfgCpu/Linker/NodeLinker.cs | 5 +- .../ParsedInstruction/CfgInstruction.cs | 11 +- .../Instructions/HltInstruction.cs | 6 +- .../Instructions/JmpNearImm.cs | 6 +- .../Instructions/JmpNearImm16.cs | 6 +- .../Instructions/JmpNearImm8.cs | 6 +- .../Instructions/MovRegImm.cs | 5 +- .../Instructions/MovRegImm16.cs | 5 +- .../Instructions/MovRegImm32.cs | 5 +- .../Instructions/MovRegImm8.cs | 5 +- .../SelfModifying/DiscriminatedNode.cs | 3 +- .../CPU/CfgCpu/Parser/InstructionParser.cs | 21 +- src/Spice86.Core/Emulator/CPU/State.cs | 2 + .../Emulator/LoadableFile/Bios/BiosLoader.cs | 2 +- .../Spice86.Tests/CfgCpu/CfgNodeFeederTest.cs | 254 ++++++++++++++++++ .../CfgCpu/InstructionsFeederTest.cs | 54 ++-- 24 files changed, 371 insertions(+), 94 deletions(-) create mode 100644 tests/Spice86.Tests/CfgCpu/CfgNodeFeederTest.cs diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/CfgNode.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/CfgNode.cs index 1b0d03e74..04e976622 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/CfgNode.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/CfgNode.cs @@ -1,13 +1,15 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ControlFlowGraph; +using Spice86.Shared.Emulator.Memory; + public abstract class CfgNode : ICfgNode { - public CfgNode(uint physicalAddress) { - PhysicalAddress = physicalAddress; + public CfgNode(SegmentedAddress address) { + Address = address; } public ISet Predecessors { get; } = new HashSet(); public ISet Successors { get; } = new HashSet(); - public uint PhysicalAddress { get; } + public SegmentedAddress Address { get; } public abstract bool IsAssembly { get; } public abstract void UpdateSuccessorCache(); diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/ICfgNode.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/ICfgNode.cs index 9305e5063..7235b272c 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/ICfgNode.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ControlFlowGraph/ICfgNode.cs @@ -1,10 +1,11 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ControlFlowGraph; +using Spice86.Shared.Emulator.Memory; + public interface ICfgNode { ISet Predecessors { get; } ISet Successors { get; } - - public uint PhysicalAddress { get; } + public SegmentedAddress Address { get; } public bool IsAssembly { get; } public void UpdateSuccessorCache(); diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CfgNodeFeeder.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CfgNodeFeeder.cs index 036731d69..32554d236 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CfgNodeFeeder.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CfgNodeFeeder.cs @@ -74,7 +74,7 @@ private ICfgNode CreateDiscriminatedNode(CfgInstruction instruction1, CfgInstruc return reducedInstructions.First(); } - DiscriminatedNode res = new DiscriminatedNode(instruction1.PhysicalAddress); + DiscriminatedNode res = new DiscriminatedNode(instruction1.Address); foreach (CfgInstruction reducedInstruction in reducedInstructions) { // Make predecessors of instructions point to res instead of instruction1/2 _nodeLinker.ReplacePredecessors(reducedInstruction, res); diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CurrentInstructions.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CurrentInstructions.cs index 23551e4c4..4bbad9424 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CurrentInstructions.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/CurrentInstructions.cs @@ -4,6 +4,7 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.Feeder; using Spice86.Core.Emulator.Memory; using Spice86.Core.Emulator.VM; using Spice86.Core.Emulator.VM.Breakpoint; +using Spice86.Shared.Emulator.Memory; /// /// Cache of current instructions in memory. @@ -17,28 +18,28 @@ public class CurrentInstructions : IInstructionReplacer { /// Instruction currently known to be in memory at a given address. /// Memory write breakpoints invalidate this cache when CPU writes there. /// - private readonly IDictionary _currentInstructionAtAddress = - new Dictionary(); + private readonly Dictionary _currentInstructionAtAddress = + new Dictionary(); /// /// Breakpoints that have been installed to monitor instruction at a given address. So that we can reset them when we want. /// - private readonly IDictionary> _breakpointsForInstruction = - new Dictionary>(); + private readonly Dictionary> _breakpointsForInstruction = + new Dictionary>(); public CurrentInstructions(IMemory memory, MachineBreakpoints machineBreakpoints) { _memory = memory; _machineBreakpoints = machineBreakpoints; } - public CfgInstruction? GetAtAddress(uint physicalAddress) { - _currentInstructionAtAddress.TryGetValue(physicalAddress, out CfgInstruction? res); + public CfgInstruction? GetAtAddress(SegmentedAddress address) { + _currentInstructionAtAddress.TryGetValue(address, out CfgInstruction? res); return res; } public void ReplaceInstruction(CfgInstruction old, CfgInstruction instruction) { - uint instructionAddress = instruction.PhysicalAddress; + SegmentedAddress instructionAddress = instruction.Address; if (_currentInstructionAtAddress.ContainsKey(instructionAddress)) { ClearCurrentInstruction(old); SetAsCurrent(instruction); @@ -54,11 +55,12 @@ public void SetAsCurrent(CfgInstruction instruction) { } private void CreateBreakpointsForInstruction(CfgInstruction instruction) { - uint instructionAddress = instruction.PhysicalAddress; + SegmentedAddress instructionAddress = instruction.Address; List breakpoints = new(); _breakpointsForInstruction.Add(instructionAddress, breakpoints); - for (uint byteAddress = instructionAddress; - byteAddress < instructionAddress + instruction.Length; + uint instructionPhysicalAddress = instructionAddress.ToPhysical(); + for (uint byteAddress = instructionPhysicalAddress; + byteAddress < instructionPhysicalAddress + instruction.Length; byteAddress++) { // When reached the breakpoint will clear the cache and the other breakpoints for the instruction AddressBreakPoint breakPoint = new AddressBreakPoint(BreakPointType.WRITE, byteAddress, @@ -81,18 +83,18 @@ private void OnBreakPointReached(BreakPoint breakPoint, CfgInstruction instructi } private void AddInstructionInCurrentCache(CfgInstruction instruction) { - uint instructionAddress = instruction.PhysicalAddress; + SegmentedAddress instructionAddress = instruction.Address; _currentInstructionAtAddress.Add(instructionAddress, instruction); } private void ClearCurrentInstruction(CfgInstruction instruction) { - uint instructionAddress = instruction.PhysicalAddress; + SegmentedAddress instructionAddress = instruction.Address; IList breakpoints = _breakpointsForInstruction[instructionAddress]; _breakpointsForInstruction.Remove(instructionAddress); foreach (AddressBreakPoint breakPoint in breakpoints) { _machineBreakpoints.ToggleBreakPoint(breakPoint, false); } - _currentInstructionAtAddress.Remove(instruction.PhysicalAddress); + _currentInstructionAtAddress.Remove(instruction.Address); } } \ No newline at end of file diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/InstructionsFeeder.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/InstructionsFeeder.cs index f6a262191..cbee8cd3d 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/InstructionsFeeder.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/InstructionsFeeder.cs @@ -26,7 +26,7 @@ public InstructionsFeeder(MachineBreakpoints machineBreakpoints, IMemory memory, } public CfgInstruction GetInstructionFromMemory(ushort segment, ushort offset) { - uint physicalAddress = MemoryUtils.ToPhysicalAddress(segment, offset); + SegmentedAddress physicalAddress = new SegmentedAddress(segment, offset); // Try to get instruction from cache that represents current memory state. CfgInstruction? current = _currentInstructions.GetAtAddress(physicalAddress); if (current != null) { diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/MemoryInstructionMatcher.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/MemoryInstructionMatcher.cs index b09ba9b44..d427ac987 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/MemoryInstructionMatcher.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/MemoryInstructionMatcher.cs @@ -17,7 +17,7 @@ public MemoryInstructionMatcher(IMemory memory) { } private bool IsMatchingWithCurrentMemory(CfgInstruction instruction) { - Span bytesInMemory = _memory.GetSpan((int)instruction.PhysicalAddress, instruction.Length); + Span bytesInMemory = _memory.GetSpan((int)instruction.Address.ToPhysical(), instruction.Length); return instruction.Discriminator.Equals(bytesInMemory); } diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/PreviousInstructions.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/PreviousInstructions.cs index bb1b5002f..6d6274dfd 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/PreviousInstructions.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/Feeder/PreviousInstructions.cs @@ -2,6 +2,7 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.Feeder; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction; using Spice86.Core.Emulator.Memory; +using Spice86.Shared.Emulator.Memory; /// /// Cache of previous instructions that existed in a memory address at a time. @@ -12,16 +13,15 @@ public class PreviousInstructions : IInstructionReplacer { /// /// Instructions that were parsed at a given address. List for address is ordered by instruction decreasing length /// - private readonly IDictionary> _previousInstructionsAtAddress = - new Dictionary>(); + private readonly Dictionary> _previousInstructionsAtAddress = new(); public PreviousInstructions(IMemory memory) { _memoryInstructionMatcher = new MemoryInstructionMatcher(memory); } - public CfgInstruction? GetAtAddress(uint physicalAddress) { - if (_previousInstructionsAtAddress.TryGetValue(physicalAddress, - out ISet? previousInstructionsAtAddress)) { + public CfgInstruction? GetAtAddress(SegmentedAddress address) { + if (_previousInstructionsAtAddress.TryGetValue(address, + out HashSet? previousInstructionsAtAddress)) { return _memoryInstructionMatcher.MatchExistingInstructionWithMemory(previousInstructionsAtAddress); } @@ -29,10 +29,10 @@ public PreviousInstructions(IMemory memory) { } public void ReplaceInstruction(CfgInstruction old, CfgInstruction instruction) { - uint instructionAddress = instruction.PhysicalAddress; + SegmentedAddress instructionAddress = instruction.Address; if (_previousInstructionsAtAddress.TryGetValue(instructionAddress, - out ISet? previousInstructionsAtAddress)) { + out HashSet? previousInstructionsAtAddress)) { if (previousInstructionsAtAddress.Remove(old)) { AddInstructionInPrevious(instruction); } @@ -40,10 +40,10 @@ public void ReplaceInstruction(CfgInstruction old, CfgInstruction instruction) { } public void AddInstructionInPrevious(CfgInstruction instruction) { - uint instructionAddress = instruction.PhysicalAddress; + SegmentedAddress instructionAddress = instruction.Address; if (!_previousInstructionsAtAddress.TryGetValue(instructionAddress, - out ISet? previousInstructionsAtAddress)) { + out HashSet? previousInstructionsAtAddress)) { previousInstructionsAtAddress = new HashSet(); _previousInstructionsAtAddress.Add(instructionAddress, previousInstructionsAtAddress); } diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/InstructionExecutor/ExecutorCfgNodeVisitor.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/InstructionExecutor/ExecutorCfgNodeVisitor.cs index 13579e727..fea86d39c 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/InstructionExecutor/ExecutorCfgNodeVisitor.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/InstructionExecutor/ExecutorCfgNodeVisitor.cs @@ -60,7 +60,7 @@ public void Accept(MovRegImm32 instruction) { } public void Accept(DiscriminatedNode discriminatedNode) { - int address = (int)discriminatedNode.PhysicalAddress; + int address = (int)discriminatedNode.Address.ToPhysical(); foreach (InstructionDiscriminator instructionDiscriminator in discriminatedNode.SuccessorsPerDiscriminator.Keys) { int length = instructionDiscriminator.DiscriminatorValue.Count; Span bytes = _memory.GetSpan(address, length); @@ -83,7 +83,7 @@ private void MoveIpToEndOfInstruction(CfgInstruction instruction) { } private ICfgNode? GetSuccessorAtCsIp(CfgInstruction instruction) { - instruction.SuccessorsPerAddress.TryGetValue(_state.IpPhysicalAddress, out ICfgNode? res); + instruction.SuccessorsPerAddress.TryGetValue(_state.IpSegmentedAddress, out ICfgNode? res); return res; } diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/Linker/NodeLinker.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/Linker/NodeLinker.cs index 0e28ec1f5..93e483fee 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/Linker/NodeLinker.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/Linker/NodeLinker.cs @@ -4,6 +4,7 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.Linker; using Spice86.Core.Emulator.CPU.CfgCpu.Feeder; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.SelfModifying; +using Spice86.Shared.Emulator.Memory; public class NodeLinker : IInstructionReplacer { /// @@ -20,8 +21,8 @@ public void Link(ICfgNode current, ICfgNode next) { } private void LinkCfgInstruction(CfgInstruction current, ICfgNode next) { - IDictionary successors = current.SuccessorsPerAddress; - if (!successors.TryGetValue(next.PhysicalAddress, out ICfgNode? shouldBeNext)) { + Dictionary successors = current.SuccessorsPerAddress; + if (!successors.TryGetValue(next.Address, out ICfgNode? shouldBeNext)) { AttachCurrentToNext(current, next); return; } diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/CfgInstruction.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/CfgInstruction.cs index a6d26cc12..a0bbf19ad 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/CfgInstruction.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/CfgInstruction.cs @@ -2,6 +2,7 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction; using Spice86.Core.Emulator.CPU.CfgCpu.ControlFlowGraph; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Prefix; +using Spice86.Shared.Emulator.Memory; using System.Linq; @@ -9,13 +10,13 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction; /// Base of all the instructions: Prefixes (optional) and an opcode that can be either one or 2 bytes. /// public abstract class CfgInstruction : CfgNode { - protected CfgInstruction(uint physicalAddress, InstructionField opcodeField) : this(physicalAddress, + protected CfgInstruction(SegmentedAddress address, InstructionField opcodeField) : this(address, opcodeField, new List()) { } - protected CfgInstruction(uint physicalAddress, InstructionField opcodeField, + protected CfgInstruction(SegmentedAddress address, InstructionField opcodeField, IList prefixes) - : base(physicalAddress) { + : base(address) { InstructionPrefixes = prefixes; PrefixFields = prefixes.Select(prefix => prefix.PrefixField).ToList(); foreach (InstructionPrefix prefix in prefixes) { @@ -42,10 +43,10 @@ public void PostInit() { /// /// Cache of Successors property per address. Maintenance is complex with self modifying code and is done by the InstructionLinker /// - public Dictionary SuccessorsPerAddress { get; private set; } = new Dictionary(); + public Dictionary SuccessorsPerAddress { get; private set; } = new Dictionary(); public override void UpdateSuccessorCache() { - SuccessorsPerAddress = Successors.ToDictionary(node => node.PhysicalAddress); + SuccessorsPerAddress = Successors.ToDictionary(node => node.Address); } public override bool IsAssembly { get => true; } diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/HltInstruction.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/HltInstruction.cs index e66ec10bd..3eb9b5bc6 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/HltInstruction.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/HltInstruction.cs @@ -1,10 +1,10 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; -using Spice86.Core.Emulator.CPU.CfgCpu.ControlFlowGraph; +using Spice86.Shared.Emulator.Memory; public class HltInstruction : CfgInstruction { - public HltInstruction(uint physicalAddress, InstructionField opcodeField) : - base(physicalAddress, opcodeField) { + public HltInstruction(SegmentedAddress address, InstructionField opcodeField) : + base(address, opcodeField) { } public override void Visit(ICfgNodeVisitor visitor) { diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm.cs index 64848baa7..55acfff1d 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm.cs @@ -1,10 +1,12 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; +using Spice86.Shared.Emulator.Memory; + using System.Numerics; public abstract class JmpNearImm : CfgInstruction where T : ISignedNumber { - public JmpNearImm(uint physicalAddress, InstructionField opcodeField, InstructionField offsetField) : - base(physicalAddress, opcodeField) { + public JmpNearImm(SegmentedAddress address, InstructionField opcodeField, InstructionField offsetField) : + base(address, opcodeField) { OffsetField = offsetField; FieldsInOrder.Add(OffsetField); } diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm16.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm16.cs index b5af66770..4b8f2e7b3 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm16.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm16.cs @@ -1,11 +1,13 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; +using Spice86.Shared.Emulator.Memory; + public class JmpNearImm16 : JmpNearImm { public override void Visit(ICfgNodeVisitor visitor) { visitor.Accept(this); } - public JmpNearImm16(uint physicalAddress, InstructionField opcodeField, InstructionField offsetField) : - base(physicalAddress, opcodeField, offsetField) { + public JmpNearImm16(SegmentedAddress address, InstructionField opcodeField, InstructionField offsetField) : + base(address, opcodeField, offsetField) { } } \ No newline at end of file diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm8.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm8.cs index 42947d59f..21135d822 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm8.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/JmpNearImm8.cs @@ -1,11 +1,13 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; +using Spice86.Shared.Emulator.Memory; + public class JmpNearImm8 : JmpNearImm { public override void Visit(ICfgNodeVisitor visitor) { visitor.Accept(this); } - public JmpNearImm8(uint physicalAddress, InstructionField opcodeField, InstructionField offsetField) : - base(physicalAddress, opcodeField, offsetField) { + public JmpNearImm8(SegmentedAddress address, InstructionField opcodeField, InstructionField offsetField) : + base(address, opcodeField, offsetField) { } } \ No newline at end of file diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm.cs index 1b2b01935..06d8a41cb 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm.cs @@ -1,16 +1,17 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Prefix; +using Spice86.Shared.Emulator.Memory; using System.Numerics; public abstract class MovRegImm : CfgInstruction where T : IUnsignedNumber { - public MovRegImm(uint physicalAddress, + public MovRegImm(SegmentedAddress address, InstructionField opcodeField, IList prefixes, InstructionField valueField, int regIndex) : - base(physicalAddress, opcodeField, prefixes) { + base(address, opcodeField, prefixes) { ValueField = valueField; FieldsInOrder.Add(ValueField); diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm16.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm16.cs index 39a3f3633..03bf12c61 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm16.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm16.cs @@ -1,13 +1,14 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Prefix; +using Spice86.Shared.Emulator.Memory; public class MovRegImm16 : MovRegImm { - public MovRegImm16(uint physicalAddress, + public MovRegImm16(SegmentedAddress address, InstructionField opcodeField, IList prefixes, InstructionField valueField, - int regIndex) : base(physicalAddress, opcodeField, prefixes, valueField, regIndex) { + int regIndex) : base(address, opcodeField, prefixes, valueField, regIndex) { } public override void Visit(ICfgNodeVisitor visitor) { diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm32.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm32.cs index 33bdc3176..7bcea953d 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm32.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm32.cs @@ -1,13 +1,14 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Prefix; +using Spice86.Shared.Emulator.Memory; public class MovRegImm32 : MovRegImm { - public MovRegImm32(uint physicalAddress, + public MovRegImm32(SegmentedAddress address, InstructionField opcodeField, IList prefixes, InstructionField valueField, - int regIndex) : base(physicalAddress, opcodeField, prefixes, valueField, regIndex) { + int regIndex) : base(address, opcodeField, prefixes, valueField, regIndex) { } public override void Visit(ICfgNodeVisitor visitor) { diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm8.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm8.cs index e5cd549d5..c5c68ec19 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm8.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/Instructions/MovRegImm8.cs @@ -1,13 +1,14 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Prefix; +using Spice86.Shared.Emulator.Memory; public class MovRegImm8 : MovRegImm { - public MovRegImm8(uint physicalAddress, + public MovRegImm8(SegmentedAddress address, InstructionField opcodeField, IList prefixes, InstructionField valueField, - int regIndex) : base(physicalAddress, opcodeField, prefixes, valueField, regIndex) { + int regIndex) : base(address, opcodeField, prefixes, valueField, regIndex) { } public override void Visit(ICfgNodeVisitor visitor) { diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/SelfModifying/DiscriminatedNode.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/SelfModifying/DiscriminatedNode.cs index 69d1ada8e..5cc8bbc9d 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/SelfModifying/DiscriminatedNode.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/ParsedInstruction/SelfModifying/DiscriminatedNode.cs @@ -1,11 +1,12 @@ namespace Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.SelfModifying; using Spice86.Core.Emulator.CPU.CfgCpu.ControlFlowGraph; +using Spice86.Shared.Emulator.Memory; using System.Linq; public class DiscriminatedNode : CfgNode { - public DiscriminatedNode(uint physicalAddress) : base(physicalAddress) { + public DiscriminatedNode(SegmentedAddress address) : base(address) { } public override bool IsAssembly => false; diff --git a/src/Spice86.Core/Emulator/CPU/CfgCpu/Parser/InstructionParser.cs b/src/Spice86.Core/Emulator/CPU/CfgCpu/Parser/InstructionParser.cs index 83021bb46..43baea8fa 100644 --- a/src/Spice86.Core/Emulator/CPU/CfgCpu/Parser/InstructionParser.cs +++ b/src/Spice86.Core/Emulator/CPU/CfgCpu/Parser/InstructionParser.cs @@ -25,10 +25,9 @@ public InstructionParser(IIndexable memory, State state) { public CfgInstruction ParseInstructionAt(SegmentedAddress address) { _instructionReader.InstructionReaderAddressSource.InstructionAddress = address; - uint physicalAddress = address.ToPhysical(); IList prefixes = ParsePrefixes(); InstructionField opcodeField = _instructionReader.UInt8.NextField(); - CfgInstruction res = ParseCfgInstruction(physicalAddress, opcodeField, prefixes); + CfgInstruction res = ParseCfgInstruction(address, opcodeField, prefixes); res.PostInit(); return res; } @@ -41,7 +40,7 @@ private bool HasAddressSize32(IList prefixes) { return prefixes.Where(p => p is AddressSize32Prefix).Any(); } - private CfgInstruction ParseCfgInstruction(uint physicalAddress, InstructionField opcodeField, + private CfgInstruction ParseCfgInstruction(SegmentedAddress address, InstructionField opcodeField, IList prefixes) { switch (opcodeField.Value) { case 0xB0: @@ -60,29 +59,29 @@ private CfgInstruction ParseCfgInstruction(uint physicalAddress, InstructionFiel case 0xBD: case 0xBE: case 0xBF: - return MovRegImm(physicalAddress, opcodeField, prefixes); - case 0xE9: return new JmpNearImm16(physicalAddress, opcodeField, _instructionReader.Int16.NextField()); - case 0xEB: return new JmpNearImm8(physicalAddress, opcodeField, _instructionReader.Int8.NextField()); - case 0xF4: return new HltInstruction(physicalAddress, opcodeField); + return MovRegImm(address, opcodeField, prefixes); + case 0xE9: return new JmpNearImm16(address, opcodeField, _instructionReader.Int16.NextField()); + case 0xEB: return new JmpNearImm8(address, opcodeField, _instructionReader.Int8.NextField()); + case 0xF4: return new HltInstruction(address, opcodeField); } return HandleInvalidOpcode(opcodeField.Value); } - private CfgInstruction MovRegImm(uint physicalAddress, InstructionField opcodeField, + private CfgInstruction MovRegImm(SegmentedAddress address, InstructionField opcodeField, IList prefixes) { int regIndex = opcodeField.Value & RegIndexMask; if ((opcodeField.Value & WordMask) == 0) { - return new MovRegImm8(physicalAddress, opcodeField, prefixes, _instructionReader.UInt8.NextField(), + return new MovRegImm8(address, opcodeField, prefixes, _instructionReader.UInt8.NextField(), regIndex); } if (HasOperandSize32(prefixes)) { - return new MovRegImm32(physicalAddress, opcodeField, prefixes, _instructionReader.UInt32.NextField(), + return new MovRegImm32(address, opcodeField, prefixes, _instructionReader.UInt32.NextField(), regIndex); } - return new MovRegImm16(physicalAddress, opcodeField, prefixes, _instructionReader.UInt16.NextField(), regIndex); + return new MovRegImm16(address, opcodeField, prefixes, _instructionReader.UInt16.NextField(), regIndex); } private IList ParsePrefixes() { diff --git a/src/Spice86.Core/Emulator/CPU/State.cs b/src/Spice86.Core/Emulator/CPU/State.cs index c00bf6718..a33008021 100644 --- a/src/Spice86.Core/Emulator/CPU/State.cs +++ b/src/Spice86.Core/Emulator/CPU/State.cs @@ -2,6 +2,7 @@ using Spice86.Core.Emulator.Debugger; using Spice86.Core.Emulator.CPU.Registers; +using Spice86.Shared.Emulator.Memory; using System.Text; @@ -108,6 +109,7 @@ public class State : IDebuggableComponent { /// public long Cycles { get; private set; } public uint IpPhysicalAddress => MemoryUtils.ToPhysicalAddress(CS, IP); + public SegmentedAddress IpSegmentedAddress => new SegmentedAddress(CS, IP); public uint StackPhysicalAddress => MemoryUtils.ToPhysicalAddress(SS, SP); public GeneralRegisters GeneralRegisters { get; } = new(); diff --git a/src/Spice86.Core/Emulator/LoadableFile/Bios/BiosLoader.cs b/src/Spice86.Core/Emulator/LoadableFile/Bios/BiosLoader.cs index 745c6e85a..cc3885468 100644 --- a/src/Spice86.Core/Emulator/LoadableFile/Bios/BiosLoader.cs +++ b/src/Spice86.Core/Emulator/LoadableFile/Bios/BiosLoader.cs @@ -47,7 +47,7 @@ public override byte[] LoadFile(string file, string? arguments) { uint physicalStartAddress = MemoryUtils.ToPhysicalAddress(CodeSegment, 0); _memory.LoadData(physicalStartAddress, bios); SetEntryPoint(CodeSegment, CodeOffset); - //_memory.Int8[MemoryUtils.ToPhysicalAddress(CodeSegment, CodeOffset)+1] = -2; + _memory.Int8[MemoryUtils.ToPhysicalAddress(CodeSegment, CodeOffset)+1] = -2; return bios; } } diff --git a/tests/Spice86.Tests/CfgCpu/CfgNodeFeederTest.cs b/tests/Spice86.Tests/CfgCpu/CfgNodeFeederTest.cs new file mode 100644 index 000000000..a3b4cc4c5 --- /dev/null +++ b/tests/Spice86.Tests/CfgCpu/CfgNodeFeederTest.cs @@ -0,0 +1,254 @@ +using NSubstitute; + +using Spice86.Core.Emulator.CPU; +using Spice86.Core.Emulator.CPU.CfgCpu.ControlFlowGraph; +using Spice86.Core.Emulator.CPU.CfgCpu.Feeder; +using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction; +using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.Instructions; +using Spice86.Core.Emulator.CPU.CfgCpu.ParsedInstruction.SelfModifying; +using Spice86.Core.Emulator.Memory; +using Spice86.Core.Emulator.VM; +using Spice86.Logging; +using Spice86.Shared.Emulator.Memory; +using Spice86.Shared.Interfaces; + +using Xunit; + +using ExecutionContext = Spice86.Core.Emulator.CPU.CfgCpu.Linker.ExecutionContext; + +namespace Spice86.Tests.CfgCpu; + +public class CfgNodeFeederTest { + private const int AxIndex = 0; + private const int BxIndex = 3; + private const int CxIndex = 1; + private const ushort DefaultValue = 0xFFFF; + private const ushort NewValue = 0x1234; + private const int MovRegImm16Length = 3; + private static SegmentedAddress ZeroAddress = new(0, 0); + private static SegmentedAddress EndOfMov0Address = new(0, MovRegImm16Length); + + private Memory _memory = new(new Ram(64), is20ThAddressLineSilenced: false); + private State _state = new(); + + private CfgNodeFeeder CreateCfgNodeFeeder() { + ILoggerService loggerService = Substitute.For(new LoggerPropertyBag()); + _memory = new(new Ram(64), is20ThAddressLineSilenced: false); + _state = new State(); + MachineBreakpoints machineBreakpoints = new MachineBreakpoints(_memory, _state, loggerService); + return new(_memory, _state, machineBreakpoints); + } + + private void WriteMovReg16(SegmentedAddress address, byte opcode, ushort value) { + _memory.UInt8[address] = opcode; + _memory.UInt16[address + 1] = value; + } + + private void WriteMovAx(SegmentedAddress address, ushort value) { + WriteMovReg16(address, 0xB8, value); + } + + private void WriteMovBx(SegmentedAddress address, ushort value) { + WriteMovReg16(address, 0xBB, value); + } + + private void WriteMovCx(SegmentedAddress address, ushort value) { + WriteMovReg16(address, 0xB9, value); + } + + private ICfgNode SimulateExecution(CfgNodeFeeder cfgNodeFeeder, ExecutionContext executionContext) { + ICfgNode node = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + executionContext.LastExecuted = node; + if (node is CfgInstruction cfgInstruction) { + _state.IP = cfgInstruction.Length; + } + return node; + } + + private void WriteTwoMovAx() { + WriteMovAx(ZeroAddress, DefaultValue); + WriteMovAx(EndOfMov0Address, DefaultValue); + } + + [Fact] + public void ReadInstructionViaParser() { + // Arrange + CfgNodeFeeder cfgNodeFeeder = CreateCfgNodeFeeder(); + ExecutionContext executionContext = new ExecutionContext(); + WriteMovAx(ZeroAddress, DefaultValue); + + // Act + ICfgNode movAx = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + + // Assert + MovRegImm16 movAxRegImm16 = AssertIsMovAx(movAx); + AssertUsesValue(movAxRegImm16, DefaultValue); + } + + [Fact] + public void LinkTwoIntructions() { + // Arrange + CfgNodeFeeder cfgNodeFeeder = CreateCfgNodeFeeder(); + ExecutionContext executionContext = new ExecutionContext(); + WriteMovAx(ZeroAddress, DefaultValue); + WriteMovBx(EndOfMov0Address, DefaultValue); + ICfgNode movAx = SimulateExecution(cfgNodeFeeder, executionContext); + + // Act + ICfgNode movBx = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + + // Assert + MovRegImm16 movAxRegImm16 = AssertIsMovAx(movAx); + MovRegImm16 movBxRegImm16 = AssertIsMovBx(movBx); + AssertUsesValue(movBxRegImm16, DefaultValue); + AssertSuccessorAtAddress(movAxRegImm16, EndOfMov0Address, movBx); + } + + [Fact] + public void MovAxChangedToMovBx() { + // Arrange + CfgNodeFeeder cfgNodeFeeder = CreateCfgNodeFeeder(); + ExecutionContext executionContext = new ExecutionContext(); + WriteTwoMovAx(); + ICfgNode movAx0 = SimulateExecution(cfgNodeFeeder, executionContext); + // Parse second Mov AX and insert it in graph + ICfgNode movAx1 = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + + + // Act + // Some time later second Mov AX changes to Mov BX and we are about to execute it, graph says next is Mov AX but this is no the case. + WriteMovBx(EndOfMov0Address, DefaultValue); + executionContext.NodeToExecuteNextAccordingToGraph = movAx1; + ICfgNode discriminated = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + + // Assert + // Mov AX0 is not anymore linked to mov ax1, there is a discriminator node between them. + AssertDoesNotLinkTo(movAx0, movAx1); + // Check the discriminator node is there + DiscriminatedNode discriminatedNode = AssertIsDiscriminatedNode(discriminated); + AssertLinksTo(movAx0, discriminatedNode); + // Check discriminator node also contains Mov BX + ICfgNode movBx = discriminated.Successors.First(node => node != movAx1); + MovRegImm16 movBxRegImm16 = AssertIsMovBx(movBx); + MovRegImm16 movAx1RegImm16 = AssertIsMovAx(movAx1); + AssertUsesValue(movBxRegImm16, DefaultValue); + AssertSuccessorAtDiscriminator(discriminatedNode, movBxRegImm16); + AssertSuccessorAtDiscriminator(discriminatedNode, movAx1RegImm16); + } + + [Fact] + public void MovAxChangedValue() { + // Arrange + CfgNodeFeeder cfgNodeFeeder = CreateCfgNodeFeeder(); + ExecutionContext executionContext = new ExecutionContext(); + WriteTwoMovAx(); + SimulateExecution(cfgNodeFeeder, executionContext); + // Just parse next and insert it in graph + ICfgNode movAx1 = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + + // Act + // We are still after movAx0 but it changed to MOV AX 1234. + WriteMovAx(EndOfMov0Address, NewValue); + executionContext.NodeToExecuteNextAccordingToGraph = movAx1; + ICfgNode shouldBeMovAx1 = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + + // Assert + // Intructions instances should be the same, no new intruction should have been created + Assert.Equal(movAx1, shouldBeMovAx1); + } + + [Fact] + public void MovAxChangedToMovBxThenMovCx() { + // Arrange + CfgNodeFeeder cfgNodeFeeder = CreateCfgNodeFeeder(); + ExecutionContext executionContext = new ExecutionContext(); + WriteTwoMovAx(); + SimulateExecution(cfgNodeFeeder, executionContext); + ICfgNode movAx1 = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + executionContext.NodeToExecuteNextAccordingToGraph = movAx1; + WriteMovBx(EndOfMov0Address, DefaultValue); + ICfgNode discriminated = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + WriteMovCx(EndOfMov0Address, DefaultValue); + // CPU executed discriminator but Mov CX was in memory => no successor of the discriminator matched + executionContext.LastExecuted = discriminated; + executionContext.NodeToExecuteNextAccordingToGraph = null; + + // Act + // We at discriminator but instruction got changed to something that is not yet in the discriminator list of values. + ICfgNode movCx = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + + // Assert + DiscriminatedNode discriminatedNode = AssertIsDiscriminatedNode(discriminated); + MovRegImm16 movCxRegImm16 = AssertIsMovCx(movCx); + AssertSuccessorAtDiscriminator(discriminatedNode, movCxRegImm16); + } + + [Fact] + public void MovAxChangedToMovBxThenMovAxWithDifferentValue() { + // Arrange + CfgNodeFeeder cfgNodeFeeder = CreateCfgNodeFeeder(); + ExecutionContext executionContext = new ExecutionContext(); + WriteTwoMovAx(); + SimulateExecution(cfgNodeFeeder, executionContext); + ICfgNode movAx1 = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + executionContext.NodeToExecuteNextAccordingToGraph = movAx1; + WriteMovBx(EndOfMov0Address, DefaultValue); + ICfgNode discriminated = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + WriteMovAx(EndOfMov0Address, NewValue); + // CPU executed discriminator node, Mov AX was in memory => matched with initial mov AX + executionContext.LastExecuted = discriminated; + executionContext.NodeToExecuteNextAccordingToGraph = movAx1; + + // Act + ICfgNode shouldBeMovAx1 = cfgNodeFeeder.GetLinkedCfgNodeToExecute(executionContext); + Assert.Equal(movAx1, shouldBeMovAx1); + } + + private void AssertSuccessorAtDiscriminator(DiscriminatedNode predecessor, CfgInstruction expectedSuccessor) { + AssertLinksTo(predecessor, expectedSuccessor); + Assert.Equal(expectedSuccessor, predecessor.SuccessorsPerDiscriminator[expectedSuccessor.Discriminator]); + } + + private void AssertSuccessorAtAddress(CfgInstruction predecessor, SegmentedAddress address, ICfgNode expectedSuccessor) { + AssertLinksTo(predecessor, expectedSuccessor); + Assert.Equal(expectedSuccessor, predecessor.SuccessorsPerAddress[address]); + } + + private void AssertLinksTo(ICfgNode previous, ICfgNode next) { + Assert.True(previous.Successors.Contains(next)); + Assert.True(next.Predecessors.Contains(previous)); + } + + private void AssertDoesNotLinkTo(ICfgNode previous, ICfgNode next) { + Assert.False(previous.Successors.Contains(next)); + Assert.False(next.Predecessors.Contains(previous)); + } + + private DiscriminatedNode AssertIsDiscriminatedNode(ICfgNode discriminated) { + Assert.Equal(typeof(DiscriminatedNode), discriminated.GetType()); + return (DiscriminatedNode)discriminated; + } + + private void AssertUsesValue(MovRegImm16 node, ushort expectedValue) { + Assert.True(node.ValueField.UseValue); + Assert.Equal(expectedValue, node.ValueField.Value); + } + + private MovRegImm16 AssertIsMovAx(ICfgNode node) { + return AssertIsMovRegImm16(node, AxIndex); + } + + private MovRegImm16 AssertIsMovBx(ICfgNode node) { + return AssertIsMovRegImm16(node, BxIndex); + } + + private MovRegImm16 AssertIsMovCx(ICfgNode node) { + return AssertIsMovRegImm16(node, CxIndex); + } + + private MovRegImm16 AssertIsMovRegImm16(ICfgNode node, int expectedRegIndex) { + Assert.Equal(typeof(MovRegImm16), node.GetType()); + Assert.Equal(expectedRegIndex, ((MovRegImm16)node).RegIndex); + return (MovRegImm16)node; + } +} \ No newline at end of file diff --git a/tests/Spice86.Tests/CfgCpu/InstructionsFeederTest.cs b/tests/Spice86.Tests/CfgCpu/InstructionsFeederTest.cs index d559058ca..d4c887a54 100644 --- a/tests/Spice86.Tests/CfgCpu/InstructionsFeederTest.cs +++ b/tests/Spice86.Tests/CfgCpu/InstructionsFeederTest.cs @@ -6,13 +6,17 @@ using Spice86.Core.Emulator.Memory; using Spice86.Core.Emulator.VM; using Spice86.Logging; +using Spice86.Shared.Emulator.Memory; using Spice86.Shared.Interfaces; using Xunit; namespace Spice86.Tests.CfgCpu; -public class InstructionsFeederTest -{ +public class InstructionsFeederTest { + private static SegmentedAddress ZeroAddress = new(0, 0); + private static SegmentedAddress TwoAddress = new(0, 2); + private static SegmentedAddress SixteenAddress = new(0, 16); + private readonly Memory _memory = new(new Ram(64), is20ThAddressLineSilenced: false); private InstructionsFeeder CreateInstructionsFeeder() @@ -24,13 +28,13 @@ private InstructionsFeeder CreateInstructionsFeeder() return new InstructionsFeeder(machineBreakpoints, _memory, state); } - private void WriteJumpNear(int address) + private void WriteJumpNear(SegmentedAddress address) { _memory.UInt8[address] = 0xEB; _memory.Int8[address + 1] = -2; } - private void WriteMovAx(int address) + private void WriteMovAx(SegmentedAddress address) { _memory.UInt8[address] = 0xB8; _memory.UInt16[address + 1] = 0xFFFF; @@ -41,7 +45,7 @@ private JmpNearImm8 CreateReplacementInstruction() var opcodeField = new InstructionField(0, 1, 0, 0xEB, new List() { 0xEB }); // Replacement has a null discriminator byte for offset field -> will not be taken into account when comparing with ram var offsetField = new InstructionField(1, 1, 1, -2, new List() { null }); - JmpNearImm8 res = new JmpNearImm8(0, opcodeField, offsetField); + JmpNearImm8 res = new JmpNearImm8(ZeroAddress, opcodeField, offsetField); res.PostInit(); return res; } @@ -51,7 +55,7 @@ public void ReadInstructionViaParser() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); // Act CfgInstruction instruction = instructionsFeeder.GetInstructionFromMemory(0, 0); @@ -65,7 +69,7 @@ public void ReadInstructionTwiceIsSameInstruction() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); // Act CfgInstruction instruction1 = instructionsFeeder.GetInstructionFromMemory(0, 0); @@ -81,13 +85,13 @@ public void ReadSeflModifyingCode() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); // Act // Read the jump instructionsFeeder.GetInstructionFromMemory(0, 0); // This should cause the breakpoints to trigger and to clear the first instruction from the first current cache ensuring address 0 will be parsed - WriteMovAx(0); + WriteMovAx(ZeroAddress); CfgInstruction instruction2 = instructionsFeeder.GetInstructionFromMemory(0, 0); @@ -100,15 +104,15 @@ public void ReadSeflModifyingCodeSameInstructionTwice() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); // Act // Read the jump CfgInstruction instruction1 = instructionsFeeder.GetInstructionFromMemory(0, 0); - WriteMovAx(0); + WriteMovAx(ZeroAddress); // Read the mov instructionsFeeder.GetInstructionFromMemory(0, 0); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); // Read the jump again CfgInstruction instruction2 = instructionsFeeder.GetInstructionFromMemory(0, 0); @@ -121,18 +125,18 @@ public void ReadSeflModifyingCodeSameInstructionTwiceThenDetectSwitchAgain() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); // Act // Read the jump instructionsFeeder.GetInstructionFromMemory(0, 0); - WriteMovAx(0); + WriteMovAx(ZeroAddress); // Read the mov instructionsFeeder.GetInstructionFromMemory(0, 0); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); // Read the jump again instructionsFeeder.GetInstructionFromMemory(0, 0); - WriteMovAx(0); + WriteMovAx(ZeroAddress); // Read the mov, normally last restore that is from "previous" cache should also have set breakpoints and so on for self modifying code detection CfgInstruction instruction2 = instructionsFeeder.GetInstructionFromMemory(0, 0); @@ -145,7 +149,7 @@ public void ReplaceInstruction() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); CfgInstruction old = instructionsFeeder.GetInstructionFromMemory(0, 0); // Act @@ -162,13 +166,13 @@ public void ReplaceInstructionAndEnsureSelfModifyingCodeIsDetected() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); CfgInstruction old = instructionsFeeder.GetInstructionFromMemory(0, 0); // Act CfgInstruction newInstruction = CreateReplacementInstruction(); instructionsFeeder.ReplaceInstruction(old, newInstruction); - WriteMovAx(0); + WriteMovAx(ZeroAddress); CfgInstruction instruction = instructionsFeeder.GetInstructionFromMemory(0, 0); // Assert @@ -180,15 +184,15 @@ public void ReplaceInstructionAndEnsureItStaysAfterSelfModifyingCode() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); CfgInstruction old = instructionsFeeder.GetInstructionFromMemory(0, 0); // Act CfgInstruction newInstruction = CreateReplacementInstruction(); instructionsFeeder.ReplaceInstruction(old, newInstruction); - WriteMovAx(0); + WriteMovAx(ZeroAddress); instructionsFeeder.GetInstructionFromMemory(0, 0); - WriteJumpNear(0); + WriteJumpNear(ZeroAddress); CfgInstruction instruction = instructionsFeeder.GetInstructionFromMemory(0, 0); // Assert @@ -200,8 +204,8 @@ public void SameInstructionAsDifferentAddressIsDifferentNode() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(0); - WriteJumpNear(2); + WriteJumpNear(ZeroAddress); + WriteJumpNear(TwoAddress); // Act CfgInstruction instructionAddress0 = instructionsFeeder.GetInstructionFromMemory(0, 0); @@ -218,7 +222,7 @@ public void SameInstructionSamePhysicalAddressDifferentSegmentedAddressIsSame() { // Arrange InstructionsFeeder instructionsFeeder = CreateInstructionsFeeder(); - WriteJumpNear(16); + WriteJumpNear(SixteenAddress); // Act CfgInstruction instruction1 = instructionsFeeder.GetInstructionFromMemory(0, 16);