diff --git a/src/Arch/X86/Analysis/FstswAnalysis.cs b/src/Arch/X86/Analysis/FstswAnalysis.cs index 4496a402c5..cced651a8b 100644 --- a/src/Arch/X86/Analysis/FstswAnalysis.cs +++ b/src/Arch/X86/Analysis/FstswAnalysis.cs @@ -19,6 +19,7 @@ #endregion using Reko.Analysis; +using Reko.Arch.X86.Rewriter; using Reko.Core; using Reko.Core.Code; using Reko.Core.Collections; diff --git a/src/Arch/X86/X86FrameApplicationBuilder.cs b/src/Arch/X86/Analysis/X86FrameApplicationBuilder.cs similarity index 96% rename from src/Arch/X86/X86FrameApplicationBuilder.cs rename to src/Arch/X86/Analysis/X86FrameApplicationBuilder.cs index be025b2a66..07b80fa9c3 100644 --- a/src/Arch/X86/X86FrameApplicationBuilder.cs +++ b/src/Arch/X86/Analysis/X86FrameApplicationBuilder.cs @@ -28,13 +28,13 @@ using Reko.Core.Operators; using Reko.Core.Analysis; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Analysis { public class X86FrameApplicationBuilder : FrameApplicationBuilder { public X86FrameApplicationBuilder( IntelArchitecture arch, - IStorageBinder binder, + IStorageBinder binder, CallSite site) : base(arch, binder, site) { diff --git a/src/Arch/X86/InstructionSet.cs b/src/Arch/X86/Disassembler/InstructionSet.cs similarity index 100% rename from src/Arch/X86/InstructionSet.cs rename to src/Arch/X86/Disassembler/InstructionSet.cs diff --git a/src/Arch/X86/X86Disassembler.0F38.cs b/src/Arch/X86/Disassembler/X86Disassembler.0F38.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.0F38.cs rename to src/Arch/X86/Disassembler/X86Disassembler.0F38.cs diff --git a/src/Arch/X86/X86Disassembler.0F3A.cs b/src/Arch/X86/Disassembler/X86Disassembler.0F3A.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.0F3A.cs rename to src/Arch/X86/Disassembler/X86Disassembler.0F3A.cs diff --git a/src/Arch/X86/X86Disassembler.Decoders.cs b/src/Arch/X86/Disassembler/X86Disassembler.Decoders.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.Decoders.cs rename to src/Arch/X86/Disassembler/X86Disassembler.Decoders.cs diff --git a/src/Arch/X86/X86Disassembler.Groups.cs b/src/Arch/X86/Disassembler/X86Disassembler.Groups.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.Groups.cs rename to src/Arch/X86/Disassembler/X86Disassembler.Groups.cs diff --git a/src/Arch/X86/X86Disassembler.OneByte.cs b/src/Arch/X86/Disassembler/X86Disassembler.OneByte.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.OneByte.cs rename to src/Arch/X86/Disassembler/X86Disassembler.OneByte.cs diff --git a/src/Arch/X86/X86Disassembler.TwoByte.cs b/src/Arch/X86/Disassembler/X86Disassembler.TwoByte.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.TwoByte.cs rename to src/Arch/X86/Disassembler/X86Disassembler.TwoByte.cs diff --git a/src/Arch/X86/X86Disassembler.cs b/src/Arch/X86/Disassembler/X86Disassembler.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.cs rename to src/Arch/X86/Disassembler/X86Disassembler.cs diff --git a/src/Arch/X86/X86Disassembler.x87.cs b/src/Arch/X86/Disassembler/X86Disassembler.x87.cs similarity index 100% rename from src/Arch/X86/X86Disassembler.x87.cs rename to src/Arch/X86/Disassembler/X86Disassembler.x87.cs diff --git a/src/Arch/X86/X86Emulator.cs b/src/Arch/X86/Emulator/X86Emulator.cs similarity index 89% rename from src/Arch/X86/X86Emulator.cs rename to src/Arch/X86/Emulator/X86Emulator.cs index aae2858cd7..da3bd0ac6d 100644 --- a/src/Arch/X86/X86Emulator.cs +++ b/src/Arch/X86/Emulator/X86Emulator.cs @@ -30,9 +30,9 @@ using System.Runtime.CompilerServices; using System.Text; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Emulator { - using TWord = System.UInt32; + using TWord = UInt32; /// /// Simple emulator of X86 instructions. No attempt is made to be high-performance @@ -47,12 +47,12 @@ public abstract class X86Emulator : EmulatorBase public const uint Dmask = 1u << 10; public const uint Omask = 1u << 11; - protected static readonly TraceSwitch trace = new TraceSwitch(nameof(X86Emulator), "Trace execution of X86 Emulator") - { + protected static readonly TraceSwitch trace = new TraceSwitch(nameof(X86Emulator), "Trace execution of X86 Emulator") + { Level = TraceLevel.Warning }; - public static readonly (uint value, uint hibit)[] masks = new(uint, uint)[]{ + public static readonly (uint value, uint hibit)[] masks = new (uint, uint)[]{ (0, 0), (0x0000_00FFu, 0x0000_0080), (0x0000_FFFFu, 0x0000_8000), @@ -87,22 +87,22 @@ public X86Emulator( : base(segmentMap) { this.arch = arch; - this.map = segmentMap; + map = segmentMap; this.ipReg = ipReg; this.cxReg = cxReg; - this.Registers = new ulong[40]; - this.iFlags = X86.Registers.eflags.Number; + Registers = new ulong[40]; + iFlags = X86.Registers.eflags.Number; this.envEmulator = envEmulator; - this.dasm = default!; - this.ip = default!; + dasm = default!; + ip = default!; } public override MachineInstruction CurrentInstruction => dasm.Current; public ulong Flags { - get { return this.Registers[iFlags]; } - set { this.Registers[iFlags] = value; } + get { return Registers[iFlags]; } + set { Registers[iFlags] = value; } } public abstract Address AddressFromWord(ulong word); @@ -126,8 +126,8 @@ public override Address InstructionPointer [MethodImpl(MethodImplOptions.AggressiveInlining)] private void UpdateIp(Address value) { - this.ip = value; - WriteRegister(this.ipReg, (TWord) value.Offset); + ip = value; + WriteRegister(ipReg, (TWord) value.Offset); if (value.Selector.HasValue) { WriteRegister(X86.Registers.cs, value.Selector.Value); @@ -274,7 +274,7 @@ protected TWord GetEffectiveOffset(MemoryOperand m) if (m.Offset != null) ea += m.Offset.ToUInt32(); if (m.Index != RegisterStorage.None) - ea += (TWord)ReadRegister(m.Index) * m.Scale; + ea += (TWord) ReadRegister(m.Index) * m.Scale; if (m.Base != null && m.Base != RegisterStorage.None) { ea += (TWord) ReadRegister(m.Base); @@ -335,7 +335,7 @@ private void Write(MachineOperand op, TWord w) public sealed override ulong WriteRegister(RegisterStorage r, ulong value) { - Registers[r.Number] = (Registers[r.Number] & ~r.BitMask) | (value << (int) r.BitAddress); + Registers[r.Number] = Registers[r.Number] & ~r.BitMask | value << (int) r.BitAddress; return value; } @@ -345,7 +345,7 @@ public void WriteMemory(TWord w, ulong ea, DataType dt) { case 1: WriteByte(ea, (byte) w); return; case 2: WriteLeUInt16(ea, (ushort) w); return; - case 4: WriteLeUInt32(ea, (uint) w); return; + case 4: WriteLeUInt32(ea, w); return; case 8: throw new NotImplementedException(); } throw new InvalidOperationException(); @@ -374,18 +374,18 @@ private void Adc(MachineOperand dst, MachineOperand src) TWord l = Read(dst); TWord r = Read(src); var mask = masks[dst.Width.Size]; - TWord sum = (l + r + ((uint)Flags & 1)) & mask.value; + TWord sum = l + r + ((uint) Flags & 1) & mask.value; Write(dst, sum); var newCy = - ((l & r) | ((l | r) & (~(sum)))) >> 31; + (l & r | (l | r) & ~sum) >> 31; - uint ov = ((~(l ^ r) & (l ^ sum)) & 0x80000000u) >> 20; + uint ov = (~(l ^ r) & (l ^ sum) & 0x80000000u) >> 20; Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= - (newCy) | // Carry + newCy | // Carry (sum == 0 ? 1u << 6 : 0u) | // Zero ((sum & mask.hibit) != 0 ? Smask : 0u) | // Sign - (ov) // Overflow + ov // Overflow ; } @@ -396,22 +396,22 @@ private void Add(MachineOperand dst, MachineOperand src) if (src.Width.Size < dst.Width.Size) r = (TWord) (sbyte) r; var mask = masks[dst.Width.Size]; - TWord sum = (l + r) & mask.value; + TWord sum = l + r & mask.value; Write(dst, sum); - uint ov = ((~(l ^ r) & (l ^ sum)) & mask.hibit) >> 20; + uint ov = (~(l ^ r) & (l ^ sum) & mask.hibit) >> 20; Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= (r > sum ? 1u : 0u) | // Carry (sum == 0 ? 1u << 6 : 0u) | // Zero ((sum & mask.hibit) != 0 ? Smask : 0u) | // Sign - (ov) // Overflow + ov // Overflow ; } private void Rep() { var strInstr = dasm.Current; - this.ignoreRep = true; + ignoreRep = true; var c = ReadRegister(cxReg); while (c != 0) { @@ -419,14 +419,14 @@ private void Rep() --c; WriteRegister(cxReg, c); } - this.ignoreRep = false; + ignoreRep = false; } // Repeat while Z flag is set. private void Repe() { var strInstr = dasm.Current; - this.ignoreRep = true; + ignoreRep = true; var c = ReadRegister(cxReg); while (c != 0) { @@ -438,13 +438,13 @@ private void Repe() if ((Flags & Zmask) == 0) break; } - this.ignoreRep = false; + ignoreRep = false; } private void Repne() { var strInstr = dasm.Current; - this.ignoreRep = true; + ignoreRep = true; var c = ReadRegister(cxReg); while (c != 0) { @@ -456,7 +456,7 @@ private void Repne() if ((Flags & Zmask) != 0) break; } - this.ignoreRep = false; + ignoreRep = false; } protected abstract void Ret(); @@ -470,9 +470,9 @@ private void Rcl(MachineOperand dst, MachineOperand src) if ((Flags & Cmask) != 0) l |= 1; byte sh = (byte) Read(src); - TWord r = (l << sh) | (l >> (dst.Width.BitSize + 1 - sh)); + TWord r = l << sh | l >> dst.Width.BitSize + 1 - sh; var mask = masks[dst.Width.Size]; - Write(dst, (r >> 1) & mask.value); + Write(dst, r >> 1 & mask.value); Flags &= ~(Cmask | Zmask); Flags |= ((r & ~1) == 0 ? Zmask : 0u) | // Zero @@ -483,11 +483,11 @@ private void Rol(MachineOperand dst, MachineOperand src) { TWord l = Read(dst); byte sh = (byte) Read(src); - TWord r = (l << sh) | (l >> (32 - sh)); + TWord r = l << sh | l >> 32 - sh; Write(dst, r); - Flags &= ~(Zmask); + Flags &= ~Zmask; Flags |= - (r == 0 ? Zmask : 0u); // Zero + r == 0 ? Zmask : 0u; // Zero } protected abstract void Lods(X86Instruction instr); @@ -502,7 +502,7 @@ private void Sar(MachineOperand dst, MachineOperand src) long l = (long) Bits.SignExtend(n, dst.Width.BitSize); byte sh = (byte) Read(src); var mask = masks[dst.Width.Size]; - TWord r = (TWord)((l >> sh) & mask.value); + TWord r = (TWord) (l >> sh & mask.value); Write(dst, r); Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= @@ -515,7 +515,7 @@ private void Shl(MachineOperand dst, MachineOperand src) TWord l = Read(dst); byte sh = (byte) Read(src); var (value, hibit) = masks[dst.Width.Size]; - TWord r = (l << sh) & value; + TWord r = l << sh & value; Write(dst, r); Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= @@ -528,11 +528,11 @@ private void Shr(MachineOperand dst, MachineOperand src) TWord l = Read(dst); byte sh = (byte) Read(src); var mask = masks[dst.Width.Size]; - TWord r = (l >> sh) & mask.value; + TWord r = l >> sh & mask.value; Write(dst, r); Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= - ((l >> (sh-1)) & 1) | // Carry + l >> sh - 1 & 1 | // Carry (r == 0 ? Zmask : 0u) | // Zero ((r & mask.hibit) != 0 ? Smask : 0u); // Sign } @@ -568,17 +568,17 @@ private void Cmp(MachineOperand dst, MachineOperand src) TWord l = Read(dst); TWord r = Read(src); if (src.Width.Size < dst.Width.Size) - r = (TWord)(sbyte)r; + r = (TWord) (sbyte) r; r = ~r + 1u; var mask = masks[dst.Width.Size]; - TWord diff = (l + r) & mask.value; - uint ov = ((~(l ^ r) & (l ^ diff)) & mask.hibit) >> 20; + TWord diff = l + r & mask.value; + uint ov = (~(l ^ r) & (l ^ diff) & mask.hibit) >> 20; Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= (l < diff ? 1u : 0u) | // Carry (diff == 0 ? Zmask : 0u) | // Zero ((diff & mask.hibit) != 0 ? Smask : 0u) | // Sign - (ov) // Overflow + ov // Overflow ; } @@ -587,18 +587,18 @@ private void Sub(MachineOperand dst, MachineOperand src) TWord l = Read(dst); TWord r = Read(src); if (src.Width.Size < dst.Width.Size) - r = (TWord)(sbyte)r; + r = (TWord) (sbyte) r; r = ~r + 1u; // Two's complement subtraction. var mask = masks[dst.Width.Size]; - TWord diff = (l + r) & mask.value; + TWord diff = l + r & mask.value; Write(dst, diff); - uint ov = ((~(l ^ r) & (l ^ diff)) & mask.hibit) >> 20; + uint ov = (~(l ^ r) & (l ^ diff) & mask.hibit) >> 20; Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= (l < diff ? 1u : 0u) | // Carry (diff == 0 ? Zmask : 0u) | // Zero ((diff & mask.hibit) != 0 ? Smask : 0u) | // Sign - (ov) // Overflow + ov // Overflow ; } @@ -607,9 +607,9 @@ private void And(MachineOperand dst, MachineOperand src) TWord l = Read(dst); TWord r = Read(src); if (src.Width.Size < dst.Width.Size) - r = (TWord)(sbyte)r; + r = (TWord) (sbyte) r; var mask = masks[dst.Width.Size]; - var and = (l & r) & mask.value; + var and = l & r & mask.value; Write(dst, and); Flags &= ~(Cmask | Zmask | Smask | Omask); Flags |= @@ -623,7 +623,7 @@ private void Not(MachineOperand op) { TWord v = Read(op); var mask = masks[op.Width.Size]; - var not = (~v) & mask.value; + var not = ~v & mask.value; Write(op, not); // Flags are not affected according to Intel docs. } @@ -633,7 +633,7 @@ private void Or(MachineOperand dst, MachineOperand src) TWord l = Read(dst); TWord r = Read(src); if (src.Width.Size < dst.Width.Size) - r = (TWord)(sbyte)r; + r = (TWord) (sbyte) r; var mask = masks[dst.Width.Size]; var or = (l | r) & mask.value; Write(dst, or); @@ -649,7 +649,7 @@ private void Dec(MachineOperand op) { TWord old = Read(op); var mask = masks[op.Width.Size]; - TWord gnu = (old - 1) & mask.value; + TWord gnu = old - 1 & mask.value; Write(op, gnu); uint ov = ((old ^ gnu) & ~gnu & mask.hibit) >> 20; Flags &= ~(Zmask | Smask | Omask); @@ -663,7 +663,7 @@ private void Inc(MachineOperand op) { TWord old = Read(op); var mask = masks[op.Width.Size]; - TWord gnu = (old + 1) & mask.value; + TWord gnu = old + 1 & mask.value; Write(op, gnu); uint ov = ((old ^ gnu) & gnu & mask.hibit) >> 20; Flags &= ~(Zmask | Smask | Omask); @@ -699,15 +699,15 @@ public void Popa() public void Pusha() { var dt = PrimitiveType.Word32; - var temp = (uint)Registers[X86.Registers.esp.Number]; - Push((uint)Registers[X86.Registers.eax.Number], dt); - Push((uint)Registers[X86.Registers.ecx.Number], dt); - Push((uint)Registers[X86.Registers.edx.Number], dt); - Push((uint)Registers[X86.Registers.ebx.Number], dt); + var temp = (uint) Registers[X86.Registers.esp.Number]; + Push((uint) Registers[X86.Registers.eax.Number], dt); + Push((uint) Registers[X86.Registers.ecx.Number], dt); + Push((uint) Registers[X86.Registers.edx.Number], dt); + Push((uint) Registers[X86.Registers.ebx.Number], dt); Push(temp, dt); - Push((uint)Registers[X86.Registers.ebp.Number], dt); - Push((uint)Registers[X86.Registers.esi.Number], dt); - Push((uint)Registers[X86.Registers.edi.Number], dt); + Push((uint) Registers[X86.Registers.ebp.Number], dt); + Push((uint) Registers[X86.Registers.esi.Number], dt); + Push((uint) Registers[X86.Registers.edi.Number], dt); } protected abstract TWord Pop(DataType dt); @@ -737,7 +737,7 @@ private void Test(MachineOperand op1, MachineOperand op2) if (op2.Width.Size < op1.Width.Size) r = (TWord) (sbyte) r; var mask = masks[op1.Width.Size]; - var test = (l & r) & mask.value; + var test = l & r & mask.value; Flags &= ~(Cmask | Zmask | Smask | Omask); //$TODO: parity. Flags |= 0 | // Clear carry diff --git a/src/Arch/X86/X86Protected32Emulator.cs b/src/Arch/X86/Emulator/X86Protected32Emulator.cs similarity index 91% rename from src/Arch/X86/X86Protected32Emulator.cs rename to src/Arch/X86/Emulator/X86Protected32Emulator.cs index 534f7d46a5..6d356cc34e 100644 --- a/src/Arch/X86/X86Protected32Emulator.cs +++ b/src/Arch/X86/Emulator/X86Protected32Emulator.cs @@ -24,18 +24,18 @@ using Reko.Core.Types; using System; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Emulator { public class X86Protected32Emulator : X86Emulator { - public X86Protected32Emulator(IntelArchitecture arch, SegmentMap segmentMap, IPlatformEmulator envEmulator) + public X86Protected32Emulator(IntelArchitecture arch, SegmentMap segmentMap, IPlatformEmulator envEmulator) : base(arch, segmentMap, envEmulator, X86.Registers.eip, X86.Registers.ecx) { } public override Address AddressFromWord(ulong word) { - return Address.Ptr32((uint)word); + return Address.Ptr32((uint) word); } protected override void Call(MachineOperand op) @@ -71,11 +71,11 @@ protected override void Scas(X86Instruction instr) var a = ReadRegister(X86.Registers.eax) & mask.value; var edi = ReadRegister(X86.Registers.edi); var value = ReadMemory(edi, dt) & mask.value; - var delta = (long) dt.Size * (((Flags & Dmask) != 0) ? -1 : 1); + var delta = (long) dt.Size * ((Flags & Dmask) != 0 ? -1 : 1); edi += (ulong) delta; WriteRegister(X86.Registers.edi, edi); Flags &= ~Zmask; - Flags |= (a == value ? Zmask : 0u); + Flags |= a == value ? Zmask : 0u; } protected override void Stos(X86Instruction dt) @@ -96,7 +96,7 @@ protected override void Push(ulong word, DataType dt) { var esp = (uint) Registers[X86.Registers.esp.Number] - 4; WriteLeUInt32(esp, (uint) word); - WriteRegister(X86.Registers.esp, (uint) esp); + WriteRegister(X86.Registers.esp, esp); } protected override void Ret() diff --git a/src/Arch/X86/X86RealModeEmulator.cs b/src/Arch/X86/Emulator/X86RealModeEmulator.cs similarity index 89% rename from src/Arch/X86/X86RealModeEmulator.cs rename to src/Arch/X86/Emulator/X86RealModeEmulator.cs index ec09062caf..51ae5d34c6 100644 --- a/src/Arch/X86/X86RealModeEmulator.cs +++ b/src/Arch/X86/Emulator/X86RealModeEmulator.cs @@ -28,11 +28,11 @@ using System.Linq; using System.Runtime.CompilerServices; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Emulator { public class X86RealModeEmulator : X86Emulator { - public X86RealModeEmulator(IntelArchitecture arch, SegmentMap segmentMap, IPlatformEmulator envEmulator) + public X86RealModeEmulator(IntelArchitecture arch, SegmentMap segmentMap, IPlatformEmulator envEmulator) : base(arch, segmentMap, envEmulator, X86.Registers.ip, X86.Registers.cx) { } @@ -65,7 +65,7 @@ protected override ulong GetEffectiveAddress(MemoryOperand m) segReg = m.DefaultSegment; var off = GetEffectiveOffset(m) & 0xFFFF; - var seg = (ushort)ReadRegister(segReg); + var seg = (ushort) ReadRegister(segReg); return ToLinear(seg, off); } @@ -77,9 +77,9 @@ protected override void Lods(X86Instruction instr) var value = ReadMemory(ToLinear(ds, si), dt); var mask = masks[dt.Size]; var a = ReadRegister(X86.Registers.eax); - var aNew = (a & ~mask.value) | value; + var aNew = a & ~mask.value | value; WriteRegister(X86.Registers.eax, aNew); - var delta = (uint) dt.Size * (((Flags & Dmask) != 0) ? 0xFFFFu : 0x0001u); + var delta = (uint) dt.Size * ((Flags & Dmask) != 0 ? 0xFFFFu : 0x0001u); si += delta; WriteRegister(X86.Registers.si, si); } @@ -93,7 +93,7 @@ protected override void Movs(X86Instruction instr) var dt = instr.dataWidth; var value = ReadMemory(ToLinear(ds, si), dt); WriteMemory(value, ToLinear(es, di), dt); - var delta = (uint)dt.Size * (((Flags & Dmask) != 0) ? 0xFFFFu : 0x0001u); + var delta = (uint) dt.Size * ((Flags & Dmask) != 0 ? 0xFFFFu : 0x0001u); si += delta; di += delta; WriteRegister(X86.Registers.si, si); @@ -117,11 +117,11 @@ protected override void Scas(X86Instruction instr) var es = ReadSegmentRegister(instr.Operands[1], X86.Registers.es); var di = (uint) ReadRegister(X86.Registers.di); var value = ReadMemory(ToLinear(es, di), dt) & mask.value; - var delta = dt.Size * (((Flags & Dmask) != 0) ? -1 : 1); + var delta = dt.Size * ((Flags & Dmask) != 0 ? -1 : 1); di += (uint) delta; WriteRegister(X86.Registers.di, di); Flags &= ~Zmask; - Flags |= (a == value ? Zmask : 0u); + Flags |= a == value ? Zmask : 0u; } protected override void Stos(X86Instruction instr) @@ -131,7 +131,7 @@ protected override void Stos(X86Instruction instr) var di = (uint) ReadRegister(X86.Registers.di); var value = (uint) (Registers[X86.Registers.rax.Number] & Bits.Mask(0, dt.BitSize)); WriteMemory(value, ToLinear(es, di), dt); - var delta = (uint) dt.Size * (((Flags & Dmask) != 0) ? 0xFFFFu : 0x0001u); + var delta = (uint) dt.Size * ((Flags & Dmask) != 0 ? 0xFFFFu : 0x0001u); di += delta; WriteRegister(X86.Registers.di, di); } @@ -149,7 +149,7 @@ protected override uint Pop(DataType dt) protected override void Push(ulong value, DataType dt) { var ss = (ushort) ReadRegister(X86.Registers.ss); - var sp = (ushort) ReadRegister(X86.Registers.sp) - (uint)dt.Size; + var sp = (ushort) ReadRegister(X86.Registers.sp) - (uint) dt.Size; WriteLeUInt16(ToLinear(ss, sp), (ushort) value); WriteRegister(X86.Registers.sp, sp); } @@ -173,7 +173,7 @@ protected override void TraceState(X86Instruction instr) new[] { "AX", "BX", "CX", "DX", "SP", "BP", "SI", "DI" } .Select(DumpReg))); Debug.Print("{0} {1}", string.Join(" ", - new[] {"DS", "ES", "SS", "CS", "IP" } + new[] { "DS", "ES", "SS", "CS", "IP" } .Select(DumpReg)), DumpFlags()); Debug.Print("{0}", DumpInstr(instr)); @@ -184,7 +184,7 @@ protected override void TraceState(X86Instruction instr) private string DumpReg(string regName) { - var regValue = this.ReadRegister(arch.GetRegister(regName.ToLower())!); + var regValue = ReadRegister(arch.GetRegister(regName.ToLower())!); return $"{regName}={regValue:X4}"; } @@ -212,12 +212,12 @@ private string DumpInstr(X86Instruction instr) private string DumpMem(X86Instruction instr) { - string sValue = "???"; + string sValue = "???"; if (instr.Mnemonic == Mnemonic.lodsb || instr.Mnemonic == Mnemonic.movsb) { var ds = (uint) ReadRegister(X86.Registers.ds); var si = (uint) ReadRegister(X86.Registers.si); - if (base.TryReadByte(ToLinear(ds, si), out var b)) + if (TryReadByte(ToLinear(ds, si), out var b)) sValue = b.ToString("X2"); return $"DS:[{si:X4}]={sValue}"; } @@ -225,7 +225,7 @@ private string DumpMem(X86Instruction instr) { var ds = (uint) ReadRegister(X86.Registers.ds); var si = (uint) ReadRegister(X86.Registers.si); - var w = base.ReadLeUInt16(ToLinear(ds, si)); + var w = ReadLeUInt16(ToLinear(ds, si)); sValue = w.ToString("X4"); return $"DS:[{si:X4}]={sValue}"; } @@ -235,12 +235,13 @@ private string DumpMem(X86Instruction instr) { try { - var value = base.Read(mem); + var value = Read(mem); if (mem.Width.Size == 1) sValue = ((byte) value).ToString("X2"); - else + else sValue = ((ushort) value).ToString("X4"); - } catch + } + catch { } return $"{mem.ToString()}={sValue}"; @@ -252,7 +253,7 @@ private string DumpMem(X86Instruction instr) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ulong ToLinear(uint seg, uint off) { - return (((ulong) seg) << 4) + off; + return ((ulong) seg << 4) + off; } } } diff --git a/src/Arch/X86/FstswChainMatcher.cs b/src/Arch/X86/FstswChainMatcher.cs deleted file mode 100644 index 8dd388b9cb..0000000000 --- a/src/Arch/X86/FstswChainMatcher.cs +++ /dev/null @@ -1,159 +0,0 @@ -#region License -/* - * Copyright (C) 1999-2023 John Källén. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#endregion - -using Reko.Core; -using Reko.Core.Code; -using Reko.Core.Machine; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Reko.Arch.X86 -{ - public class FstswChainMatcher - { - X86Instruction [] instrs; - Dictionary zappedInstructions; - List rewritten; - OperandRewriter orw; - - /* - * the C0 bit becomes the CF (carry) flag, - the C2 bit becomes the PF(parity) flag, and - the C3 bit becomes the ZF (zero) flag. - */ - // > 0 - // < 1 - // = 40 - // inordered 45 - - public FstswChainMatcher(X86Instruction[] instrs, OperandRewriter orw) - { - this.instrs = instrs; - this.orw = orw; - this.zappedInstructions = new Dictionary(); - this.rewritten = new List(); - } - - public bool Matches(int iStart) - { - int i = iStart; - if (instrs[i].Mnemonic != Mnemonic.fstsw) - return false; - ++i; - if (i >= instrs.Length) - return false; - if (instrs[i].Mnemonic == Mnemonic.sahf) - { - zappedInstructions.Add(i, Mnemonic.nop); - rewritten.Add(new Assignment( - orw.FlagGroup(Registers.SCZO), - orw.AluRegister(Registers.FPUF))); - return true; - } - if (instrs[i].Mnemonic == Mnemonic.test) - { - if (!(instrs[i].Operands[0] is RegisterStorage acc)) - return false; - if (!(instrs[i].Operands[1] is ImmediateOperand imm)) - return false; - int mask = imm.Value.ToInt32(); - if (acc == Registers.ax || acc == Registers.eax) - mask >>= 8; - else if (acc != Registers.ah) - return false; - zappedInstructions.Add(i, Mnemonic.nop); - rewritten.Add(new Assignment( - orw.FlagGroup(Registers.SCZO), - orw.AluRegister(Registers.FPUF))); - - i = FindConditionalJumpInstruction(++i); - if (i < 0) - return false; - switch (instrs[i].Mnemonic) - { - case Mnemonic.jz: - if (mask == 0x40) - { - zappedInstructions.Add(i, Mnemonic.jnz); - return true; - } - if (mask == 0x01) - { - zappedInstructions.Add(i, Mnemonic.jge); - return true; - } - if (mask == 0x41) - { - zappedInstructions.Add(i, Mnemonic.jg); - return true; - } - break; - case Mnemonic.jnz: - if (mask == 0x40) - { - zappedInstructions.Add(i, Mnemonic.jz); - return true; - } - if (mask == 0x01) - { - zappedInstructions.Add(i, Mnemonic.jl); - return true; - } - if (mask == 0x41) - { - zappedInstructions.Add(i, Mnemonic.jle); - return true; - } - break; - } - return false; - } - return false; - } - - private int FindConditionalJumpInstruction(int i) - { - while (i < instrs.Length) - { - switch (instrs[i].Mnemonic) - { - case Mnemonic.jz: - case Mnemonic.jnz: - return i; - } - ++i; - } - return -1; - } - - public void Rewrite(CodeEmitter emitter) - { - foreach (var de in this.zappedInstructions) - { - instrs[de.Key].Mnemonic = de.Value; - } - foreach (Instruction instr in rewritten) - { - emitter.Emit(instr); - } - } - } -} diff --git a/src/Arch/X86/ProcessorMode.cs b/src/Arch/X86/ProcessorMode.cs index 70b81795da..bd4d56ded9 100644 --- a/src/Arch/X86/ProcessorMode.cs +++ b/src/Arch/X86/ProcessorMode.cs @@ -18,6 +18,8 @@ */ #endregion +using Reko.Arch.X86.Emulator; +using Reko.Arch.X86.Rewriter; using Reko.Core; using Reko.Core.Emulation; using Reko.Core.Expressions; diff --git a/src/Arch/X86/OperandRewriter.cs b/src/Arch/X86/Rewriter/OperandRewriter.cs similarity index 99% rename from src/Arch/X86/OperandRewriter.cs rename to src/Arch/X86/Rewriter/OperandRewriter.cs index 5247456980..9013beceb8 100644 --- a/src/Arch/X86/OperandRewriter.cs +++ b/src/Arch/X86/Rewriter/OperandRewriter.cs @@ -27,11 +27,11 @@ using System.Diagnostics; using Reko.Core.Lib; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { /// /// Helper class used by the X86 rewriter to turn machine code operands into - /// IL expressions. + /// s. /// public abstract class OperandRewriter { diff --git a/src/Arch/X86/X86Rewriter.Alu.cs b/src/Arch/X86/Rewriter/X86Rewriter.Alu.cs similarity index 99% rename from src/Arch/X86/X86Rewriter.Alu.cs rename to src/Arch/X86/Rewriter/X86Rewriter.Alu.cs index 45442d1f57..d93f82502f 100644 --- a/src/Arch/X86/X86Rewriter.Alu.cs +++ b/src/Arch/X86/Rewriter/X86Rewriter.Alu.cs @@ -25,7 +25,7 @@ using System; using System.Diagnostics; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { /// /// Rewrite rules for simple ALU operations. diff --git a/src/Arch/X86/X86Rewriter.Control.cs b/src/Arch/X86/Rewriter/X86Rewriter.Control.cs similarity index 99% rename from src/Arch/X86/X86Rewriter.Control.cs rename to src/Arch/X86/Rewriter/X86Rewriter.Control.cs index 1826de1ca0..06b286a2ba 100644 --- a/src/Arch/X86/X86Rewriter.Control.cs +++ b/src/Arch/X86/Rewriter/X86Rewriter.Control.cs @@ -27,7 +27,7 @@ using System; using System.Diagnostics; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { /// /// Rewrite rules for control flow instructions. diff --git a/src/Arch/X86/X86Rewriter.Ext.cs b/src/Arch/X86/Rewriter/X86Rewriter.Ext.cs similarity index 99% rename from src/Arch/X86/X86Rewriter.Ext.cs rename to src/Arch/X86/Rewriter/X86Rewriter.Ext.cs index 43671bb609..f45ed5e195 100644 --- a/src/Arch/X86/X86Rewriter.Ext.cs +++ b/src/Arch/X86/Rewriter/X86Rewriter.Ext.cs @@ -22,7 +22,7 @@ using Reko.Core.Expressions; using Reko.Core.Types; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { /// /// Rewriter support for "extended" instructions of the x86 architecture. diff --git a/src/Arch/X86/X86Rewriter.Fpu.cs b/src/Arch/X86/Rewriter/X86Rewriter.Fpu.cs similarity index 99% rename from src/Arch/X86/X86Rewriter.Fpu.cs rename to src/Arch/X86/Rewriter/X86Rewriter.Fpu.cs index 9425afcdd1..9a9ebe1522 100644 --- a/src/Arch/X86/X86Rewriter.Fpu.cs +++ b/src/Arch/X86/Rewriter/X86Rewriter.Fpu.cs @@ -25,7 +25,7 @@ using Reko.Core.Types; using System; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { public partial class X86Rewriter { diff --git a/src/Arch/X86/X86Rewriter.Sse.cs b/src/Arch/X86/Rewriter/X86Rewriter.Sse.cs similarity index 99% rename from src/Arch/X86/X86Rewriter.Sse.cs rename to src/Arch/X86/Rewriter/X86Rewriter.Sse.cs index bf807dcf83..d9c79ce104 100644 --- a/src/Arch/X86/X86Rewriter.Sse.cs +++ b/src/Arch/X86/Rewriter/X86Rewriter.Sse.cs @@ -25,7 +25,7 @@ using System; using System.Numerics; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { public partial class X86Rewriter { diff --git a/src/Arch/X86/X86Rewriter.StringIntrinsics.cs b/src/Arch/X86/Rewriter/X86Rewriter.StringIntrinsics.cs similarity index 99% rename from src/Arch/X86/X86Rewriter.StringIntrinsics.cs rename to src/Arch/X86/Rewriter/X86Rewriter.StringIntrinsics.cs index 7d62e29c76..71446ff173 100644 --- a/src/Arch/X86/X86Rewriter.StringIntrinsics.cs +++ b/src/Arch/X86/Rewriter/X86Rewriter.StringIntrinsics.cs @@ -23,7 +23,7 @@ using Reko.Core.Intrinsics; using Reko.Core.Types; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { /// /// Rewrite string intrinsics(strlen, memcpy, etc.). diff --git a/src/Arch/X86/X86Rewriter.cs b/src/Arch/X86/Rewriter/X86Rewriter.cs similarity index 99% rename from src/Arch/X86/X86Rewriter.cs rename to src/Arch/X86/Rewriter/X86Rewriter.cs index 273586f122..fd7a118678 100644 --- a/src/Arch/X86/X86Rewriter.cs +++ b/src/Arch/X86/Rewriter/X86Rewriter.cs @@ -33,7 +33,7 @@ using IEnumerator = System.Collections.IEnumerator; using ProcedureCharacteristics = Reko.Core.Serialization.ProcedureCharacteristics; -namespace Reko.Arch.X86 +namespace Reko.Arch.X86.Rewriter { /// /// Rewrites x86 instructions into a stream of low-level RTL-like instructions. diff --git a/src/Arch/X86/X86ProcessorArchitecture.cs b/src/Arch/X86/X86ProcessorArchitecture.cs index e5cc0e7b9a..a3f62725d1 100644 --- a/src/Arch/X86/X86ProcessorArchitecture.cs +++ b/src/Arch/X86/X86ProcessorArchitecture.cs @@ -20,6 +20,7 @@ using Reko.Analysis; using Reko.Arch.X86.Analysis; +using Reko.Arch.X86.Rewriter; using Reko.Core; using Reko.Core.Analysis; using Reko.Core.Assemblers; diff --git a/src/UnitTests/Arch/X86/X86FrameApplicationBuilderTests.cs b/src/UnitTests/Arch/X86/Analysis/X86FrameApplicationBuilderTests.cs similarity index 91% rename from src/UnitTests/Arch/X86/X86FrameApplicationBuilderTests.cs rename to src/UnitTests/Arch/X86/Analysis/X86FrameApplicationBuilderTests.cs index eb57ee6dd5..cd195d431a 100644 --- a/src/UnitTests/Arch/X86/X86FrameApplicationBuilderTests.cs +++ b/src/UnitTests/Arch/X86/Analysis/X86FrameApplicationBuilderTests.cs @@ -20,6 +20,7 @@ using NUnit.Framework; using Reko.Arch.X86; +using Reko.Arch.X86.Analysis; using Reko.Core; using Reko.Core.Code; using Reko.Core.Expressions; @@ -31,7 +32,7 @@ using System.Linq; using System.Text; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Analysis { [TestFixture] public class X86FrameApplicationBuilderTests @@ -44,14 +45,14 @@ public class X86FrameApplicationBuilderTests [SetUp] public void Setup() { - this.arch = new X86ArchitectureFlat32(new ServiceContainer(), "x86-protected-32", new Dictionary()); - this.frame = arch.CreateFrame(); - this.callee = frame.EnsureRegister(Registers.eax); + arch = new X86ArchitectureFlat32(new ServiceContainer(), "x86-protected-32", new Dictionary()); + frame = arch.CreateFrame(); + callee = frame.EnsureRegister(Registers.eax); } private void CreateApplicationBuilder(CallSite site) { - this.fab = new X86FrameApplicationBuilder( + fab = new X86FrameApplicationBuilder( arch, frame, site); diff --git a/src/UnitTests/Arch/X86/IntelAssemblerTests.cs b/src/UnitTests/Arch/X86/Assembler/IntelAssemblerTests.cs similarity index 54% rename from src/UnitTests/Arch/X86/IntelAssemblerTests.cs rename to src/UnitTests/Arch/X86/Assembler/IntelAssemblerTests.cs index b01a222149..cdae4440ce 100644 --- a/src/UnitTests/Arch/X86/IntelAssemblerTests.cs +++ b/src/UnitTests/Arch/X86/Assembler/IntelAssemblerTests.cs @@ -25,23 +25,23 @@ using NUnit.Framework; using System; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Assembler { - [TestFixture] - public class IntelAssemblerTests - { - [Test] - public void IntegralConstant32() - { - Constant c; - c = X86Assembler.IntegralConstant(-2, PrimitiveType.Word32); - Assert.AreSame(PrimitiveType.SByte, c.DataType); - c = X86Assembler.IntegralConstant(-128, PrimitiveType.Word32); - Assert.AreSame(PrimitiveType.SByte, c.DataType); - c = X86Assembler.IntegralConstant(-129, PrimitiveType.Word32); - Assert.AreSame(PrimitiveType.Word32, c.DataType); - c = X86Assembler.IntegralConstant(-129, PrimitiveType.Word16); - Assert.AreSame(PrimitiveType.Word16, c.DataType); - } - } + [TestFixture] + public class IntelAssemblerTests + { + [Test] + public void IntegralConstant32() + { + Constant c; + c = X86Assembler.IntegralConstant(-2, PrimitiveType.Word32); + Assert.AreSame(PrimitiveType.SByte, c.DataType); + c = X86Assembler.IntegralConstant(-128, PrimitiveType.Word32); + Assert.AreSame(PrimitiveType.SByte, c.DataType); + c = X86Assembler.IntegralConstant(-129, PrimitiveType.Word32); + Assert.AreSame(PrimitiveType.Word32, c.DataType); + c = X86Assembler.IntegralConstant(-129, PrimitiveType.Word16); + Assert.AreSame(PrimitiveType.Word16, c.DataType); + } + } } diff --git a/src/UnitTests/Arch/X86/X86DisassemblerTests.cs b/src/UnitTests/Arch/X86/Disassembler/X86DisassemblerTests.cs similarity index 99% rename from src/UnitTests/Arch/X86/X86DisassemblerTests.cs rename to src/UnitTests/Arch/X86/Disassembler/X86DisassemblerTests.cs index 5580ae2a45..8b026f0a63 100644 --- a/src/UnitTests/Arch/X86/X86DisassemblerTests.cs +++ b/src/UnitTests/Arch/X86/Disassembler/X86DisassemblerTests.cs @@ -34,7 +34,7 @@ using System.Linq; using System.Text; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Disassembler { [TestFixture] public class X86DisassemblerTests @@ -47,7 +47,7 @@ public X86DisassemblerTests() { sc = new ServiceContainer(); sc.AddService(new FileSystemServiceImpl()); - Reko.Arch.X86.X86Disassembler.traceVex.Level = System.Diagnostics.TraceLevel.Verbose; + X86Disassembler.traceVex.Level = System.Diagnostics.TraceLevel.Verbose; } private X86Instruction Disassemble16(params byte[] bytes) @@ -1721,7 +1721,7 @@ public void X86Dis_vpmovzxbq() [Test] public void X86Dis_vpmovzxbq_broken() - { + { AssertCode64("vpmovzxbq\tzmm6{k7},qword ptr [ecx]", "67 62F27D4F 32 31"); } @@ -1778,7 +1778,7 @@ public void X86Dis_vpbroadcastw() [Test] public void X86Dis_vbroadcastsd() - { + { AssertCode64("vbroadcastsd\tzmm6,qword ptr [rcx]", "62F2FD48 19 31"); } @@ -2153,7 +2153,7 @@ public void X86Dis_vcvtpd2dq() [Test] public void X86Dis_vcvtpd2dq_masked() { - AssertCode64("vcvtpd2dq\tymm6{k7},[ecx]","67 62F1FF4F E6 31"); + AssertCode64("vcvtpd2dq\tymm6{k7},[ecx]", "67 62F1FF4F E6 31"); } [Test] @@ -2492,8 +2492,8 @@ public void X86Dis_shufps() [Test] public void X86dis_vrndscale() { - AssertCode64("vrndscalepd\tymm30,ymm29,{sae},7Bh","62 03 FD 38 09 F5 7B"); - AssertCode64("vrndscaleps\tymm30,ymm29,{sae},0ABh","62 03 7D 38 08 F5 AB"); + AssertCode64("vrndscalepd\tymm30,ymm29,{sae},7Bh", "62 03 FD 38 09 F5 7B"); + AssertCode64("vrndscaleps\tymm30,ymm29,{sae},0ABh", "62 03 7D 38 08 F5 AB"); AssertCode64("vrndscalesd\txmm30,xmm28,{sae},0ABh", "62 03 95 30 0B F4 AB"); AssertCode64("vrndscaless\txmm30,xmm28,{sae},0ABh", "62 03 15 30 0A F4 AB"); } @@ -2515,7 +2515,7 @@ public void X86Dis_vshufps_VEX() [Test] public void X86Dis_vshufps_EVEX() { - AssertCode64("vshufps\tzmm6,zmm5,dword ptr [rdx+1FCh]{1to16},7Bh","62 F1 54 58 C6 72 7F 7B"); + AssertCode64("vshufps\tzmm6,zmm5,dword ptr [rdx+1FCh]{1to16},7Bh", "62 F1 54 58 C6 72 7F 7B"); } [Test] @@ -2667,7 +2667,7 @@ public void X86Dis_vcmpgt_oqps() [Test] public void X86Dis_vpcmpgtq_mask() { - AssertCode64("vpcmpgtq\tk5{k7},xmm6,qword ptr [rdx-400h]{1to2}","62 F2 CD 1F 37 6A 80"); + AssertCode64("vpcmpgtq\tk5{k7},xmm6,qword ptr [rdx-400h]{1to2}", "62 F2 CD 1F 37 6A 80"); } [Test] @@ -2829,11 +2829,11 @@ public void X86Dis_OperandRendering() [Test] public void X86Dis_pextrX() { - AssertCode64("pextrb\tebx,xmm0,4h", "66 0f 3a 14 C3 04"); - AssertCode64("pextrb\tbyte ptr [rbx],xmm0,4h", "66 0F 3A 14 03 04"); - AssertCode64("pextrd\tebx,xmm0,4h", "66 0F 3A 16 C3 04"); + AssertCode64("pextrb\tebx,xmm0,4h", "66 0f 3a 14 C3 04"); + AssertCode64("pextrb\tbyte ptr [rbx],xmm0,4h", "66 0F 3A 14 03 04"); + AssertCode64("pextrd\tebx,xmm0,4h", "66 0F 3A 16 C3 04"); AssertCode64("pextrd\tdword ptr [rbx],xmm0,4h", "66 0F 3A 16 03 04"); - AssertCode64("pextrq\trbx,xmm0,4h", "66 48 0f 3a 16 c3 04"); + AssertCode64("pextrq\trbx,xmm0,4h", "66 48 0f 3a 16 c3 04"); AssertCode64("pextrq\tqword ptr [rbx],xmm0,4h", "66 48 0f 3a 16 03 04"); } diff --git a/src/UnitTests/Arch/X86/X86Disassembler_32bit_Tests.cs b/src/UnitTests/Arch/X86/Disassembler/X86Disassembler_32bit_Tests.cs similarity index 98% rename from src/UnitTests/Arch/X86/X86Disassembler_32bit_Tests.cs rename to src/UnitTests/Arch/X86/Disassembler/X86Disassembler_32bit_Tests.cs index 8de80f446d..a480fd63f2 100644 --- a/src/UnitTests/Arch/X86/X86Disassembler_32bit_Tests.cs +++ b/src/UnitTests/Arch/X86/Disassembler/X86Disassembler_32bit_Tests.cs @@ -28,9 +28,9 @@ using System.Collections.Generic; using System.Linq; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Disassembler { - [TestFixture] + [TestFixture] public class X86Disassembler_32bit_Tests : DisassemblerTestBase { private readonly X86ArchitectureFlat32 arch; @@ -38,8 +38,8 @@ public class X86Disassembler_32bit_Tests : DisassemblerTestBase public X86Disassembler_32bit_Tests() { - this.arch = new X86ArchitectureFlat32(CreateServiceContainer(), "x86-protected-32", new Dictionary()); - this.addr = Address.Ptr32(0x10000); + arch = new X86ArchitectureFlat32(CreateServiceContainer(), "x86-protected-32", new Dictionary()); + addr = Address.Ptr32(0x10000); } public override IProcessorArchitecture Architecture => arch; @@ -53,7 +53,7 @@ private void AssertCode32(string sExp, string hexBytes) private void AssertCode32(string sExp, params byte[] bytes) { - var instr = base.DisassembleBytes(bytes); + var instr = DisassembleBytes(bytes); Assert.AreEqual(sExp, instr.ToString()); } @@ -199,7 +199,7 @@ public void X86Dis_cwde32() public void X86Dis_DirectOperand32() { var instr = DisassembleBytes(0x8B, 0x15, 0x22, 0x33, 0x44, 0x55, 0x66); - Assert.AreEqual("mov\tedx,[55443322h]", instr.ToString()); + Assert.AreEqual("mov\tedx,[55443322h]", instr.ToString()); var memOp = (MemoryOperand) instr.Operands[1]; Assert.AreEqual("word32", memOp.Offset.DataType.ToString()); } @@ -360,7 +360,7 @@ public void X86dis_invd() public void X86Dis_instr_tool_long_prefixes() { AssertCode32("xor\teax,fs:[eax]", "64 64 64 64 64 64 64 64 64 64 64 64 64 33 00"); - AssertCode32("illegal", "64 64 64 64 64 64 64 64 64 64 64 64 64 64 33 00"); + AssertCode32("illegal", "64 64 64 64 64 64 64 64 64 64 64 64 64 64 33 00"); } [Test] @@ -911,7 +911,7 @@ public void X86dis_rcpps() AssertCode32("rcpps\txmm0,[edx+42h]", 0x0F, 0x53, 0x42, 0x42); } - + [Test] public void X86dis_rdmsr() diff --git a/src/UnitTests/Arch/X86/X86Disassembler_8086_Tests.cs b/src/UnitTests/Arch/X86/Disassembler/X86Disassembler_8086_Tests.cs similarity index 93% rename from src/UnitTests/Arch/X86/X86Disassembler_8086_Tests.cs rename to src/UnitTests/Arch/X86/Disassembler/X86Disassembler_8086_Tests.cs index c289de2b72..8474fc75e7 100644 --- a/src/UnitTests/Arch/X86/X86Disassembler_8086_Tests.cs +++ b/src/UnitTests/Arch/X86/Disassembler/X86Disassembler_8086_Tests.cs @@ -28,21 +28,21 @@ using System.Text; using System.Threading.Tasks; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Disassembler { [TestFixture] public class X86Disassembler_8086_Tests : DisassemblerTestBase { public X86Disassembler_8086_Tests() { - this.Architecture = new X86ArchitectureReal( + Architecture = new X86ArchitectureReal( CreateServiceContainer(), "x86-real-16", new Dictionary { { ProcessorOption.InstructionSet, "8086" } }); - this.LoadAddress = Address.SegPtr(0x800, 0); + LoadAddress = Address.SegPtr(0x800, 0); } public override IProcessorArchitecture Architecture { get; } public override Address LoadAddress { get; } diff --git a/src/UnitTests/Arch/X86/X86EmulatorTests.cs b/src/UnitTests/Arch/X86/Emulator/X86EmulatorTests.cs similarity index 96% rename from src/UnitTests/Arch/X86/X86EmulatorTests.cs rename to src/UnitTests/Arch/X86/Emulator/X86EmulatorTests.cs index 50b237ce87..d475918322 100644 --- a/src/UnitTests/Arch/X86/X86EmulatorTests.cs +++ b/src/UnitTests/Arch/X86/Emulator/X86EmulatorTests.cs @@ -22,6 +22,7 @@ using NUnit.Framework; using Reko.Arch.X86; using Reko.Arch.X86.Assembler; +using Reko.Arch.X86.Emulator; using Reko.Core; using Reko.Core.Emulation; using Reko.Core.Loading; @@ -35,7 +36,7 @@ using System.Linq; using System.Text; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Emulator { [TestFixture] public class X86EmulatorTests @@ -66,15 +67,15 @@ private void Given_Win32Code(Action coder) var asm = new X86Assembler(arch, Address.Ptr32(0x00100000), new List()); coder(asm); var program = asm.GetImage(); - this.segmentMap = program.SegmentMap; + segmentMap = program.SegmentMap; Given_Platform(); var win32 = new Win32Emulator(program.SegmentMap, platform, importReferences); - + emu = (X86Emulator) arch.CreateEmulator(program.SegmentMap, win32); emu.InstructionPointer = program.ImageMap.BaseAddress; - emu.WriteRegister(Registers.esp, (uint)program.ImageMap.BaseAddress.ToLinear() + 0x0FFC); + emu.WriteRegister(Registers.esp, (uint) program.ImageMap.BaseAddress.ToLinear() + 0x0FFC); emu.ExceptionRaised += delegate { throw new Exception(); }; } @@ -88,7 +89,7 @@ private void Given_MsdosCode(Action coder) coder(asm); asm.Align(0x2000); // make room for a stack. var program = asm.GetImage(); - this.segmentMap = program.SegmentMap; + segmentMap = program.SegmentMap; Given_Platform(); @@ -112,9 +113,9 @@ private void Given_Platform() .Returns(new ExternalProcedure("", new FunctionType())); mockPlatform.Setup(p => p.CreateEmulator( It.IsAny(), - It.IsAny>())) + It.IsAny>())) .Returns(emu.Object); - this.platform = mockPlatform.Object; + platform = mockPlatform.Object; } // Calculate a segmented real mode address. @@ -157,7 +158,7 @@ public void X86Emu_Add32_ov() emu.Start(); Assert.AreEqual(0, emu.Registers[Registers.eax.Number]); - Assert.AreEqual(1 | (1 << 6) | (1 << 11), emu.Flags, "Should set carry + z + ov"); + Assert.AreEqual(1 | 1 << 6 | 1 << 11, emu.Flags, "Should set carry + z + ov"); } @@ -165,10 +166,11 @@ public void X86Emu_Add32_ov() [Test] public void X86Emu_Sub32_ov() { - Given_Win32Code(m => { + Given_Win32Code(m => + { m.Mov(m.eax, ~0x7FFFFFFF); m.Mov(m.ebx, 0x00000001); - m.Sub(m.eax, m.ebx); + m.Sub(m.eax, m.ebx); }); emu.Start(); @@ -190,16 +192,17 @@ public void X86Emu_Sub32_cy() emu.Start(); Assert.AreEqual(0xFFFFFFFCu, emu.Registers[Registers.eax.Number]); - Assert.AreEqual(X86Emulator.Cmask|X86Emulator.Smask, emu.Flags, "Should set C, S flags"); + Assert.AreEqual(X86Emulator.Cmask | X86Emulator.Smask, emu.Flags, "Should set C, S flags"); } [Test] public void X86Emu_ReadDirect_W32() { - Given_Win32Code(m => { + Given_Win32Code(m => + { m.Label("datablob"); m.Dd(0x12345678); - m.Mov(m.eax, m.MemDw("datablob")); + m.Mov(m.eax, m.MemDw("datablob")); }); emu.InstructionPointer += 4; emu.Start(); @@ -263,7 +266,7 @@ public void X86Emu_Immediate_W16() Given_RegValue(Registers.eax, 0xFFFFFFFF); emu.Start(); - Assert.AreEqual(0xFFFF1234u, emu.Registers[(int)Registers.eax.Domain]); + Assert.AreEqual(0xFFFF1234u, emu.Registers[(int) Registers.eax.Domain]); } [Test] @@ -281,7 +284,8 @@ public void X86Emu_Xor() [Test] public void X86Emu_or() { - Given_Win32Code(m => { + Given_Win32Code(m => + { m.Mov(m.eax, m.Imm(0x80000000)); m.Or(m.eax, m.Imm(1)); }); @@ -295,7 +299,8 @@ public void X86Emu_or() [Test] public void X86Emu_halt() { - Given_Win32Code(m => { + Given_Win32Code(m => + { m.Hlt(); m.Mov(m.eax, 42); }); @@ -331,10 +336,10 @@ public void X86Emu_pusha() m.Pusha(); m.Hlt(); m.Dw(0); - m.Dd(0); m.Dd(0); m.Dd(0); m.Dd(0); - m.Dd(0); m.Dd(0); m.Dd(0); m.Dd(0); + m.Dd(0); m.Dd(0); m.Dd(0); m.Dd(0); + m.Dd(0); m.Dd(0); m.Dd(0); m.Dd(0); }); - emu.WriteRegister(Registers.esp, (uint)segmentMap.BaseAddress.ToLinear() + 0x24u); + emu.WriteRegister(Registers.esp, (uint) segmentMap.BaseAddress.ToLinear() + 0x24u); emu.Start(); @@ -394,7 +399,7 @@ public void X86Emu_add_signextendedImmByte() Given_Win32Code(m => { m.Mov(m.esi, -0x4); - m.Db(0x83,0xEE,0xFC); // sub esi,-4 + m.Db(0x83, 0xEE, 0xFC); // sub esi,-4 }); emu.Start(); diff --git a/src/UnitTests/Arch/X86/FstswChainMatcherTests.cs b/src/UnitTests/Arch/X86/FstswChainMatcherTests.cs deleted file mode 100644 index 9c37e615de..0000000000 --- a/src/UnitTests/Arch/X86/FstswChainMatcherTests.cs +++ /dev/null @@ -1,134 +0,0 @@ -#region License -/* - * Copyright (C) 1999-2023 John Källén. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#endregion - -using Reko.Arch.X86; -using Reko.Arch.X86.Assembler; -using Reko.Core; -using Reko.Core.Code; -using Reko.Core.Types; -using Reko.UnitTests.Mocks; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Reko.Core.Expressions; -using System.ComponentModel.Design; -using Reko.Core.Loading; - -namespace Reko.UnitTests.Arch.X86 -{ - [TestFixture] - [Ignore("Disabled until we come up with a mechanism to perform architecture-specific expression simplifications, at which point this should go to Analysis")] - public class FstswChainMatcherTests - { - IntelArchitecture arch; - ProcedureBuilder emitter; - X86Assembler asm; - OperandRewriter orw; - List instrs; - - [SetUp] - public void Fstsw_Setup() - { - arch = new X86ArchitectureFlat32(new ServiceContainer(), "x86-protected-32", new Dictionary()); - asm = new X86Assembler(arch, Address.Ptr32(0x10000), new List()); - Procedure proc = new Procedure(arch, "test", Address.Ptr32(0x00123400), arch.CreateFrame()); - orw = new OperandRewriter32(arch, new ExpressionEmitter(), proc.Frame, null); - emitter = new ProcedureBuilder(); - } - - [Test] - public void Fstsw_FailMatch() - { - asm.Mov(asm.ax, asm.Const(1)); - var m = GetMatcher(); - Assert.IsFalse(m.Matches(0)); - } - - [Test] - public void Fstsw_MatchSahfSequence() - { - asm.Fstsw(asm.ax); - asm.Sahf(); - var m = GetMatcher(); - Assert.IsTrue(m.Matches(0)); - } - - [Test] - public void Fstsw_EmitSahf() - { - asm.Fstsw(asm.ax); - asm.Sahf(); - var m = GetMatcher(); - m.Matches(0); - m.Rewrite(emitter); - Assert.AreEqual(1, emitter.Block.Statements.Count); - Assert.AreEqual("SCZO = FPUF", emitter.Block.Statements[0].ToString()); - Assert.AreEqual(Reko.Arch.X86.Mnemonic.nop, instrs[1].Mnemonic); - } - - [Test] - public void Fstsw_MatchTestAh40() - { - asm.Fstsw(asm.ax); - asm.Test(asm.ah, asm.Const(0x40)); - asm.Jz("foo"); - var m = GetMatcher(); - Assert.IsTrue(m.Matches(0)); - } - - [Test] - public void Fstsw_EmitTestAh40() - { - asm.Fstsw(asm.ax); - asm.Test(asm.ah, asm.Const(0x40)); - asm.Jnz("foo"); - var m = GetMatcher(); - Assert.AreEqual(Reko.Arch.X86.Mnemonic.jnz, instrs[2].Mnemonic); - Assert.IsTrue(m.Matches(0)); - m.Rewrite(emitter); - Assert.AreEqual(1, emitter.Block.Statements.Count); - Assert.AreEqual("SCZO = FPUF", emitter.Block.Statements[0].ToString()); - Assert.AreEqual(Reko.Arch.X86.Mnemonic.jz, instrs[2].Mnemonic); - } - - [Test] - public void Fstsw_EmitTestAx01() - { - asm.Fstsw(asm.ax); - asm.Test(asm.ax, asm.Const(0x0100)); - asm.Jz("foo"); - var m = GetMatcher(); - Assert.IsTrue(m.Matches(0)); - m.Rewrite(emitter); - Assert.AreEqual(Reko.Arch.X86.Mnemonic.jge, instrs[2].Mnemonic); - } - - private FstswChainMatcher GetMatcher() - { - Program lr = asm.GetImage(); - var dasm = arch.CreateDisassembler( - lr.SegmentMap.Segments.Values.First().MemoryArea.CreateLeReader(0)); - instrs = new List(); - return new FstswChainMatcher(dasm.Cast().ToArray(), orw); - } - } -} diff --git a/src/UnitTests/Arch/X86/OperandRewriterTests.cs b/src/UnitTests/Arch/X86/OperandRewriterTests.cs deleted file mode 100644 index d05a973323..0000000000 --- a/src/UnitTests/Arch/X86/OperandRewriterTests.cs +++ /dev/null @@ -1,262 +0,0 @@ -#region License -/* - * Copyright (C) 1999-2023 John Källén. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#endregion - -using Reko.Arch.X86; -using Reko.Core; -using Reko.Core.Expressions; -using Reko.Core.Machine; -using Reko.Core.Types; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using Reko.Core.Serialization; -using System.ComponentModel.Design; -using Reko.Core.Memory; -using Reko.Core.Loading; - -namespace Reko.UnitTests.Arch.X86 -{ - [TestFixture] - public class OperandRewriterTests - { - private OperandRewriter orw; - private IntelArchitecture arch; - private Procedure proc; - private Program program; - private X86Instruction instr; - - [Test] - public void X86Orw32_Creation() - { - } - - [OneTimeSetUp] - public void GlobalSetup() - { - arch = new X86ArchitectureFlat32(new ServiceContainer(), "x86-protected-32", new Dictionary()); - } - - [SetUp] - public void Setup() - { - var mem = new ByteMemoryArea(Address.Ptr32(0x10000), new byte[4]); - program = new Program - { - SegmentMap = new SegmentMap( - mem.BaseAddress, - new ImageSegment(".text", mem, AccessMode.ReadExecute)) - }; - var procAddress = Address.Ptr32(0x10000000); - instr = new X86Instruction(Mnemonic.nop, InstrClass.Linear, PrimitiveType.Word32, PrimitiveType.Word32) - { - Address = procAddress, - }; - proc = Procedure.Create(arch, procAddress, arch.CreateFrame()); - orw = new OperandRewriter32(arch, new ExpressionEmitter(), proc.Frame, new FakeRewriterHost(program)); - } - - [Test] - public void X86Orw32_Register() - { - var r = Registers.ebp; - var id = (Identifier) orw.Transform(null, r, r.DataType); - Assert.AreEqual("ebp", id.Name); - Assert.IsNotNull(proc.Frame.FramePointer); - } - - [Test] - public void X86Orw32_Immediate() - { - var imm = ImmediateOperand.Word16(0x0003); - var c = (Constant) orw.Transform(null, imm, imm.Width); - Assert.AreEqual("3<16>", c.ToString()); - } - - [Test] - public void X86Orw32_ImmediateExtend() - { - var imm = ImmediateOperand.SByte(-1); - var c = (Constant) orw.Transform(null, imm, PrimitiveType.Word16); - Assert.AreEqual("0xFFFF<16>", c.ToString()); - } - - [Test] - public void X86Orw32_Fpu() - { - FpuOperand f = new FpuOperand(3); - var id = orw.Transform(instr, f, PrimitiveType.Real64); - Assert.AreEqual(PrimitiveType.Real64, id.DataType); - } - - [Test] - public void X86Orw32_MemAccess() - { - MemoryOperand mem = new MemoryOperand(PrimitiveType.Word32); - mem.Base = Registers.ecx; - mem.Offset = Constant.Word32(4); - Expression expr = orw.Transform(instr, mem, PrimitiveType.Word32); - Assert.AreEqual("Mem0[ecx + 4<32>:word32]", expr.ToString()); - } - - [Test] - public void X86Orw32_IndexedAccess() - { - MemoryOperand mem = new MemoryOperand(PrimitiveType.Word32, Registers.eax, Registers.edx, 4, Constant.Word32(0x24)); - Expression expr = orw.Transform(instr, mem, PrimitiveType.Word32); - Assert.AreEqual("Mem0[eax + 0x24<32> + edx * 4<32>:word32]", expr.ToString()); - } - - [Test] - public void X86Orw32_AddrOf() - { - Identifier eax = orw.AluRegister(Registers.eax); - UnaryExpression ptr = orw.AddrOf(eax); - Assert.AreEqual("&eax", ptr.ToString()); - } - - [Test] - public void X86Orw32_AluRegister() - { - Assert.AreEqual("si", orw.AluRegister(Registers.esi, PrimitiveType.Word16).ToString()); - } - } - - public class FakeRewriterHost : IRewriterHost - { - private readonly Program program; - private readonly Dictionary callSignatures; - private readonly Dictionary procedures; - - public FakeRewriterHost(Program program) - { - this.program = program; - callSignatures = new Dictionary(); - procedures = new Dictionary(); - } - - public Constant GlobalRegisterValue => null; - - public void AddCallSignature(Address addr, FunctionType sig) - { - callSignatures[addr] = sig; - } - - public void AddProcedureAtAddress(Address addr, Procedure proc) - { - procedures[addr] = proc; - } - - #region IRewriterHost Members - - public void AddCallEdge(Procedure caller, Statement stm, Procedure callee) - { - } - - public EndianImageReader CreateImageReader(Address addr) - { - throw new NotImplementedException(); - } - - public FunctionType GetCallSignatureAtAddress(Address addrCallInstruction) - { - if (callSignatures.TryGetValue(addrCallInstruction, out FunctionType sig)) - return sig; - else - return null; - } - - public Procedure[] GetAddressesFromVector(Address addrCaller, int cbReturnAddress) - { - return null; - } - - public Procedure[] GetProceduresFromVector(Address addrCaller, int cbReturnAddress) - { - return Array.Empty(); - } - - public Expression GetImport(Address addrTunk, Address addrInstruction) - { - return null; - } - - public ExternalProcedure GetImportedProcedure(IProcessorArchitecture arch, Address addrTunk, Address addrInstruction) - { - return null; - } - - public Procedure GetProcedureAtAddress(Address addr, int cbStackDepth) - { - return procedures.TryGetValue(addr, out Procedure proc) ? proc : null; - } - - public Procedure [] GetProceduresFromVector(Address vectorAddress) - { - return Array.Empty(); - } - - public ByteMemoryArea Image - { - get { throw new NotImplementedException(); } - } - - public SystemService SystemCallAt(Address addr) - { - // TODO: Add FakeRewriterHost.SystemCallAt implementation - return null; - } - - public bool TryRead(IProcessorArchitecture arch, Address addr, PrimitiveType dt, out Constant value) - { - throw new NotImplementedException(); - } - - public void AddDiagnostic(Address addr, Diagnostic d) - { - Console.Write(d.GetType().Name); - Console.Write(" - "); - Console.WriteLine(addr.ToString()); - Console.Write(": "); - Console.WriteLine(d.Message); - } - - #endregion - - public IProcessorArchitecture GetArchitecture(string archLabel) - { - throw new NotImplementedException(); - } - - public ExternalProcedure GetInterceptedCall(IProcessorArchitecture arch, Address addrImportThunk) - { - throw new NotImplementedException(); - } - - public void Error(Address address, string format, params object[] args) - { - throw new NotImplementedException(); - } - - public void Warn(Address address, string format, params object[] args) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/UnitTests/Arch/X86/OperandRewriterRealModeTests.cs b/src/UnitTests/Arch/X86/Rewriter/OperandRewriterRealModeTests.cs similarity index 70% rename from src/UnitTests/Arch/X86/OperandRewriterRealModeTests.cs rename to src/UnitTests/Arch/X86/Rewriter/OperandRewriterRealModeTests.cs index d51d0f6188..d50053ad29 100644 --- a/src/UnitTests/Arch/X86/OperandRewriterRealModeTests.cs +++ b/src/UnitTests/Arch/X86/Rewriter/OperandRewriterRealModeTests.cs @@ -29,19 +29,20 @@ using Reko.Core.Memory; using System.Collections.Generic; using Reko.Core.Loading; +using Reko.Arch.X86.Rewriter; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Rewriter { /// /// Tests for operator rewriting when dealing with real mode. /// [TestFixture] - public class OperandRewriterRealModeTests - { - private OperandRewriter orw; - private IntelArchitecture arch; + public class OperandRewriterRealModeTests + { + private OperandRewriter orw; + private IntelArchitecture arch; private X86State state; - private Procedure proc; + private Procedure proc; private X86Instruction instr; [OneTimeSetUp] @@ -50,33 +51,33 @@ public void Setup() var sc = new ServiceContainer(); arch = new X86ArchitectureReal(sc, "x86-real-16", new Dictionary()); var mem = new ByteMemoryArea(Address.Ptr32(0x10000), new byte[4]); - var program = new Program( + var program = new Program( new SegmentMap( mem.BaseAddress, new ImageSegment( "code", mem, AccessMode.ReadWriteExecute)), arch, new DefaultPlatform(sc, arch)); - var procAddress = Address.Ptr32(0x10000000); + var procAddress = Address.Ptr32(0x10000000); instr = new X86Instruction(Mnemonic.nop, InstrClass.Linear, PrimitiveType.Word16, PrimitiveType.Word16) { Address = procAddress, }; proc = Procedure.Create(arch, procAddress, arch.CreateFrame()); - orw = new OperandRewriter16(arch, new ExpressionEmitter(), proc.Frame, new FakeRewriterHost(program)); - state = (X86State)arch.CreateProcessorState(); + orw = new OperandRewriter16(arch, new ExpressionEmitter(), proc.Frame, new FakeRewriterHost(program)); + state = (X86State) arch.CreateProcessorState(); } - [Test] - public void X86Orw16_RewriteSegConst() - { - var m = new MemoryOperand( - PrimitiveType.Byte, - Registers.bx, - Constant.Int32(32)); - var e = orw.CreateMemoryAccess(instr, m); - Assert.AreEqual("Mem0[ds:bx + 0x20<16>:byte]", e.ToString()); - } - } + [Test] + public void X86Orw16_RewriteSegConst() + { + var m = new MemoryOperand( + PrimitiveType.Byte, + Registers.bx, + Constant.Int32(32)); + var e = orw.CreateMemoryAccess(instr, m); + Assert.AreEqual("Mem0[ds:bx + 0x20<16>:byte]", e.ToString()); + } + } } diff --git a/src/UnitTests/Arch/X86/Rewriter/OperandRewriterTests.cs b/src/UnitTests/Arch/X86/Rewriter/OperandRewriterTests.cs new file mode 100644 index 0000000000..6db59ed44a --- /dev/null +++ b/src/UnitTests/Arch/X86/Rewriter/OperandRewriterTests.cs @@ -0,0 +1,263 @@ +#region License +/* + * Copyright (C) 1999-2023 John Källén. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#endregion + +using Reko.Arch.X86; +using Reko.Core; +using Reko.Core.Expressions; +using Reko.Core.Machine; +using Reko.Core.Types; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using Reko.Core.Serialization; +using System.ComponentModel.Design; +using Reko.Core.Memory; +using Reko.Core.Loading; +using Reko.Arch.X86.Rewriter; + +namespace Reko.UnitTests.Arch.X86.Rewriter +{ + [TestFixture] + public class OperandRewriterTests + { + private OperandRewriter orw; + private IntelArchitecture arch; + private Procedure proc; + private Program program; + private X86Instruction instr; + + [Test] + public void X86Orw32_Creation() + { + } + + [OneTimeSetUp] + public void GlobalSetup() + { + arch = new X86ArchitectureFlat32(new ServiceContainer(), "x86-protected-32", new Dictionary()); + } + + [SetUp] + public void Setup() + { + var mem = new ByteMemoryArea(Address.Ptr32(0x10000), new byte[4]); + program = new Program + { + SegmentMap = new SegmentMap( + mem.BaseAddress, + new ImageSegment(".text", mem, AccessMode.ReadExecute)) + }; + var procAddress = Address.Ptr32(0x10000000); + instr = new X86Instruction(Mnemonic.nop, InstrClass.Linear, PrimitiveType.Word32, PrimitiveType.Word32) + { + Address = procAddress, + }; + proc = Procedure.Create(arch, procAddress, arch.CreateFrame()); + orw = new OperandRewriter32(arch, new ExpressionEmitter(), proc.Frame, new FakeRewriterHost(program)); + } + + [Test] + public void X86Orw32_Register() + { + var r = Registers.ebp; + var id = (Identifier) orw.Transform(null, r, r.DataType); + Assert.AreEqual("ebp", id.Name); + Assert.IsNotNull(proc.Frame.FramePointer); + } + + [Test] + public void X86Orw32_Immediate() + { + var imm = ImmediateOperand.Word16(0x0003); + var c = (Constant) orw.Transform(null, imm, imm.Width); + Assert.AreEqual("3<16>", c.ToString()); + } + + [Test] + public void X86Orw32_ImmediateExtend() + { + var imm = ImmediateOperand.SByte(-1); + var c = (Constant) orw.Transform(null, imm, PrimitiveType.Word16); + Assert.AreEqual("0xFFFF<16>", c.ToString()); + } + + [Test] + public void X86Orw32_Fpu() + { + FpuOperand f = new FpuOperand(3); + var id = orw.Transform(instr, f, PrimitiveType.Real64); + Assert.AreEqual(PrimitiveType.Real64, id.DataType); + } + + [Test] + public void X86Orw32_MemAccess() + { + MemoryOperand mem = new MemoryOperand(PrimitiveType.Word32); + mem.Base = Registers.ecx; + mem.Offset = Constant.Word32(4); + Expression expr = orw.Transform(instr, mem, PrimitiveType.Word32); + Assert.AreEqual("Mem0[ecx + 4<32>:word32]", expr.ToString()); + } + + [Test] + public void X86Orw32_IndexedAccess() + { + MemoryOperand mem = new MemoryOperand(PrimitiveType.Word32, Registers.eax, Registers.edx, 4, Constant.Word32(0x24)); + Expression expr = orw.Transform(instr, mem, PrimitiveType.Word32); + Assert.AreEqual("Mem0[eax + 0x24<32> + edx * 4<32>:word32]", expr.ToString()); + } + + [Test] + public void X86Orw32_AddrOf() + { + Identifier eax = orw.AluRegister(Registers.eax); + UnaryExpression ptr = orw.AddrOf(eax); + Assert.AreEqual("&eax", ptr.ToString()); + } + + [Test] + public void X86Orw32_AluRegister() + { + Assert.AreEqual("si", orw.AluRegister(Registers.esi, PrimitiveType.Word16).ToString()); + } + } + + public class FakeRewriterHost : IRewriterHost + { + private readonly Program program; + private readonly Dictionary callSignatures; + private readonly Dictionary procedures; + + public FakeRewriterHost(Program program) + { + this.program = program; + callSignatures = new Dictionary(); + procedures = new Dictionary(); + } + + public Constant GlobalRegisterValue => null; + + public void AddCallSignature(Address addr, FunctionType sig) + { + callSignatures[addr] = sig; + } + + public void AddProcedureAtAddress(Address addr, Procedure proc) + { + procedures[addr] = proc; + } + + #region IRewriterHost Members + + public void AddCallEdge(Procedure caller, Statement stm, Procedure callee) + { + } + + public EndianImageReader CreateImageReader(Address addr) + { + throw new NotImplementedException(); + } + + public FunctionType GetCallSignatureAtAddress(Address addrCallInstruction) + { + if (callSignatures.TryGetValue(addrCallInstruction, out FunctionType sig)) + return sig; + else + return null; + } + + public Procedure[] GetAddressesFromVector(Address addrCaller, int cbReturnAddress) + { + return null; + } + + public Procedure[] GetProceduresFromVector(Address addrCaller, int cbReturnAddress) + { + return Array.Empty(); + } + + public Expression GetImport(Address addrTunk, Address addrInstruction) + { + return null; + } + + public ExternalProcedure GetImportedProcedure(IProcessorArchitecture arch, Address addrTunk, Address addrInstruction) + { + return null; + } + + public Procedure GetProcedureAtAddress(Address addr, int cbStackDepth) + { + return procedures.TryGetValue(addr, out Procedure proc) ? proc : null; + } + + public Procedure[] GetProceduresFromVector(Address vectorAddress) + { + return Array.Empty(); + } + + public ByteMemoryArea Image + { + get { throw new NotImplementedException(); } + } + + public SystemService SystemCallAt(Address addr) + { + // TODO: Add FakeRewriterHost.SystemCallAt implementation + return null; + } + + public bool TryRead(IProcessorArchitecture arch, Address addr, PrimitiveType dt, out Constant value) + { + throw new NotImplementedException(); + } + + public void AddDiagnostic(Address addr, Diagnostic d) + { + Console.Write(d.GetType().Name); + Console.Write(" - "); + Console.WriteLine(addr.ToString()); + Console.Write(": "); + Console.WriteLine(d.Message); + } + + #endregion + + public IProcessorArchitecture GetArchitecture(string archLabel) + { + throw new NotImplementedException(); + } + + public ExternalProcedure GetInterceptedCall(IProcessorArchitecture arch, Address addrImportThunk) + { + throw new NotImplementedException(); + } + + public void Error(Address address, string format, params object[] args) + { + throw new NotImplementedException(); + } + + public void Warn(Address address, string format, params object[] args) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/UnitTests/Arch/X86/Rewrite32.cs b/src/UnitTests/Arch/X86/Rewriter/Rewrite32.cs similarity index 69% rename from src/UnitTests/Arch/X86/Rewrite32.cs rename to src/UnitTests/Arch/X86/Rewriter/Rewrite32.cs index 34474243bd..8f6dea2ad3 100644 --- a/src/UnitTests/Arch/X86/Rewrite32.cs +++ b/src/UnitTests/Arch/X86/Rewriter/Rewrite32.cs @@ -35,11 +35,11 @@ using System.IO; using System.Threading; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Rewriter { - [TestFixture] - public class Rewrite32 - { + [TestFixture] + public class Rewrite32 + { private Win32Platform win32; private IntelArchitecture arch; private ServiceContainer services; @@ -49,12 +49,12 @@ public class Rewrite32 public void Setup() { eventListener = new FakeDecompilerEventListener(); - this.services = new ServiceContainer(); + services = new ServiceContainer(); var tlSvc = new TypeLibraryLoaderServiceImpl(services); var configSvc = new Mock(); var win32env = new PlatformDefinition { - TypeLibraries = + TypeLibraries = { new TypeLibraryDefinition { Name= "msvcrt.xml" }, new TypeLibraryDefinition { Name= "windows32.xml" }, @@ -68,70 +68,70 @@ public void Setup() services.AddService(typeof(IEventListener), eventListener); services.AddService(typeof(IDecompilerEventListener), eventListener); services.AddService(typeof(CancellationTokenSource), new CancellationTokenSource()); - services.AddService(typeof(IFileSystemService),new FileSystemServiceImpl()); + services.AddService(typeof(IFileSystemService), new FileSystemServiceImpl()); arch = new X86ArchitectureFlat32(services, "x86-protected-32", new Dictionary()); win32 = new Win32Platform(services, arch); } - [Test] - public void RwAutoArray32() - { - RunTest("Fragments/autoarray32.asm", "Arch/X86/RwAutoArray32.txt"); - } + [Test] + public void RwAutoArray32() + { + RunTest("Fragments/autoarray32.asm", "Arch/X86/RwAutoArray32.txt"); + } - [Test] + [Test] [Category(Categories.IntegrationTests)] - public void RwMallocFree() - { - RunTest("Fragments/import32/mallocfree.asm", "Arch/X86/RwMallocFree.txt"); - } + public void RwMallocFree() + { + RunTest("Fragments/import32/mallocfree.asm", "Arch/X86/RwMallocFree.txt"); + } - [Test] + [Test] [Category(Categories.IntegrationTests)] - public void RwFrame32() - { - RunTest("Fragments/multiple/frame32.asm", "Arch/X86/RwFrame32.txt"); - } + public void RwFrame32() + { + RunTest("Fragments/multiple/frame32.asm", "Arch/X86/RwFrame32.txt"); + } - [Test] + [Test] [Category(Categories.IntegrationTests)] public void RwFtol() - { - RunTest("Fragments/import32/ftol.asm", "Arch/X86/RwFtol.txt"); - } + { + RunTest("Fragments/import32/ftol.asm", "Arch/X86/RwFtol.txt"); + } - [Test] + [Test] [Category(Categories.IntegrationTests)] - public void RwGlobalHandle() - { - RunTest("Fragments/import32/GlobalHandle.asm", "Arch/X86/RwGlobalHandle.txt"); - } + public void RwGlobalHandle() + { + RunTest("Fragments/import32/GlobalHandle.asm", "Arch/X86/RwGlobalHandle.txt"); + } - [Test] + [Test] [Category(Categories.IntegrationTests)] - public void RwLoopMalloc() - { - RunTest("Fragments/import32/loopmalloc.asm", "Arch/X86/RwLoopMalloc.txt"); - } + public void RwLoopMalloc() + { + RunTest("Fragments/import32/loopmalloc.asm", "Arch/X86/RwLoopMalloc.txt"); + } - [Test] + [Test] [Category(Categories.IntegrationTests)] - public void RwLoopGetDC() - { - RunTest("Fragments/import32/loop_GetDC.asm", "Arch/X86/RwLoopGetDC.txt"); - } - - [Test] - public void RwReg00006() - { - RunTest("Fragments/regressions/r00006.asm", "Arch/X86/RwReg00006.txt"); - } - - [Test] - public void RwSwitch32() - { - RunTest("Fragments/switch32.asm", "Arch/X86/RwSwitch32.txt"); - } + public void RwLoopGetDC() + { + RunTest("Fragments/import32/loop_GetDC.asm", "Arch/X86/RwLoopGetDC.txt"); + } + + [Test] + public void RwReg00006() + { + RunTest("Fragments/regressions/r00006.asm", "Arch/X86/RwReg00006.txt"); + } + + [Test] + public void RwSwitch32() + { + RunTest("Fragments/switch32.asm", "Arch/X86/RwSwitch32.txt"); + } [Test] public void RwSwitchReg00001() @@ -149,8 +149,8 @@ public void RwNotFoundImport() } private void RunTest(string sourceFile, string outputFile) - { - Program program; + { + Program program; var asm = new X86TextAssembler(new X86ArchitectureFlat32(services, "x86-protected-32", new Dictionary())); using (StreamReader rdr = new StreamReader(FileUnitTester.MapTestPath(sourceFile))) { @@ -174,15 +174,15 @@ private void RunTest(string sourceFile, string outputFile) } scan.ScanImage(); - using (FileUnitTester fut = new FileUnitTester(outputFile)) - { - foreach (Procedure proc in program.Procedures.Values) - { - proc.Write(true, fut.TextWriter); - fut.TextWriter.WriteLine(); - } - fut.AssertFilesEqual(); - } - } - } + using (FileUnitTester fut = new FileUnitTester(outputFile)) + { + foreach (Procedure proc in program.Procedures.Values) + { + proc.Write(true, fut.TextWriter); + fut.TextWriter.WriteLine(); + } + fut.AssertFilesEqual(); + } + } + } } diff --git a/src/UnitTests/Arch/X86/RewriteFpuInstructionTests.cs b/src/UnitTests/Arch/X86/Rewriter/RewriteFpuInstructionTests.cs similarity index 96% rename from src/UnitTests/Arch/X86/RewriteFpuInstructionTests.cs rename to src/UnitTests/Arch/X86/Rewriter/RewriteFpuInstructionTests.cs index 137742f2d3..75d7f429db 100644 --- a/src/UnitTests/Arch/X86/RewriteFpuInstructionTests.cs +++ b/src/UnitTests/Arch/X86/Rewriter/RewriteFpuInstructionTests.cs @@ -21,6 +21,7 @@ using NUnit.Framework; using Reko.Arch.X86; using Reko.Arch.X86.Assembler; +using Reko.Arch.X86.Rewriter; using Reko.Core; using Reko.Core.Loading; using Reko.Core.Memory; @@ -31,7 +32,7 @@ using System.ComponentModel.Design; using System.Linq; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Rewriter { [TestFixture] public class RewriteFpuInstructionTests : Arch.RewriterTestBase @@ -63,7 +64,7 @@ protected override IEnumerable GetRtlStream(MemoryArea im { return new X86Rewriter( arch, - host, + host, new X86State(arch), asmResult.SegmentMap.Segments.Values.First().MemoryArea.CreateLeReader(0), binder); } diff --git a/src/UnitTests/Arch/X86/Rewriter/RewriterTests.cs b/src/UnitTests/Arch/X86/Rewriter/RewriterTests.cs new file mode 100644 index 0000000000..d2d356bf21 --- /dev/null +++ b/src/UnitTests/Arch/X86/Rewriter/RewriterTests.cs @@ -0,0 +1,317 @@ +#region License +/* + * Copyright (C) 1999-2023 John Källén. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#endregion + +using Moq; +using NUnit.Framework; +using Reko.Arch.X86; +using Reko.Arch.X86.Assembler; +using Reko.Core; +using Reko.Core.Assemblers; +using Reko.Core.Code; +using Reko.Core.Configuration; +using Reko.Core.Loading; +using Reko.Core.Serialization; +using Reko.Core.Services; +using Reko.Environments.Msdos; +using Reko.Loading; +using Reko.Scanning; +using Reko.Services; +using Reko.UnitTests.Mocks; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.IO; + +namespace Reko.UnitTests.Arch.X86.Rewriter +{ + public class RewriterTestBase + { + private ServiceContainer sc; + private string configFile; + protected IAssembler asm; + protected Program program; + protected Scanner scanner; + protected Address baseAddress; + + public RewriterTestBase() + { + baseAddress = Address.SegPtr(0x0C00, 0); + } + + [SetUp] + public void SetUp() + { + sc = new ServiceContainer(); + sc.AddService(new UnitTestGenerationService(sc)); + sc.AddService(new FileSystemServiceImpl()); + var arch = new X86ArchitectureReal(sc, "x86-real-16", new Dictionary()); + program = new Program() { Architecture = arch }; + asm = new X86TextAssembler(arch); + configFile = null; + } + + public string ConfigFile + { + get { return configFile; } + set { configFile = value; } + } + + protected Procedure DoRewrite(string code) + { + program = asm.AssembleFragment(baseAddress, code); + program.Platform = new MsdosPlatform(sc, program.Architecture); + DoRewriteCore(); + return program.Procedures.Values[0]; + } + + private void DoRewriteCore() + { + var cfgSvc = new Mock(); + var env = new Mock(); + var tlSvc = new Mock(); + var eventListener = new FakeDecompilerEventListener(); + cfgSvc.Setup(c => c.GetEnvironment("ms-dos")).Returns(env.Object); + env.Setup(e => e.TypeLibraries).Returns(new List()); + env.Setup(e => e.CharacteristicsLibraries).Returns(new List()); + sc.AddService(new FakeDecompiledFileService()); + sc.AddService(eventListener); + sc.AddService(eventListener); + sc.AddService(cfgSvc.Object); + sc.AddService(tlSvc.Object); + + Project project = LoadProject(); + project.Programs.Add(this.program); + scanner = new Scanner( + this.program, + project.LoadedMetadata, + new DynamicLinker(project, this.program, eventListener), + sc); + var ep = ImageSymbol.Procedure(this.program.Architecture, baseAddress); + this.program.EntryPoints.Add(ep.Address, ep); + var program = project.Programs[0]; + foreach (var sp in program.User.Procedures.Values) + { + scanner.EnqueueUserProcedure(program.Architecture, sp); + } + scanner.ScanImage(); + } + + private Project LoadProject() + { + Project project = null; + if (configFile != null) + { + var absFile = FileUnitTester.MapTestPath(configFile); + var fsSvc = sc.RequireService(); + using Stream stm = fsSvc.CreateFileStream(absFile, FileMode.Open, FileAccess.Read, FileShare.Read); + project = new ProjectLoader( + null, + new Loader(sc), + ImageLocation.FromUri(absFile), + new FakeDecompilerEventListener()) + .LoadProject(stm); + } + else + { + project = new Project(); + } + return project; + } + + protected void DoRewriteFile(string relativePath) + { + using (var stm = new StreamReader(FileUnitTester.MapTestPath(relativePath))) + { + var lr = asm.Assemble(baseAddress, stm); + program.SegmentMap = lr.SegmentMap; + program.ImageMap = lr.ImageMap; + program.Platform = lr.Platform ?? new MsdosPlatform(sc, lr.Architecture); + } + DoRewriteCore(); + } + } + + /// + /// Unit Tests for the Intel code rewriter. + /// + + [TestFixture] + public class RewriterTests : RewriterTestBase + { + [Test] + public void RwSimpleTest() + { + DoRewrite( + @" .i86 + mov ax,0x0000 + mov cx,0x10 + add ax,cx + ret +"); + + Assert.AreEqual(1, program.Procedures.Count); + Procedure proc = program.Procedures.Values[0]; + Assert.AreEqual(3, proc.ControlGraph.Blocks.Count); // Entry, code, Exit + + Block block = new List(proc.ControlGraph.Successors(proc.EntryBlock))[0]; + Assert.AreEqual(5, block.Statements.Count); + Assignment instr1 = (Assignment) block.Statements[0].Instruction; + Assert.AreEqual("ax = 0<16>", block.Statements[0].Instruction.ToString()); + + Assert.AreSame(new List(proc.ControlGraph.Successors(block))[0], proc.ExitBlock); + } + + [Test] + public void X86Rw_real_IfTest() + { + Procedure proc = DoRewrite( + @" .i86 + cmp bx,ax + jnz not_eq + + mov cx,3 + jmp join +not_eq: + mov cx,2 +join: + ret +"); + Assert.AreEqual(6, proc.ControlGraph.Blocks.Count); + StringWriter sb = new StringWriter(); + proc.Write(true, sb); + } + + [Test] + public void RwDeadConditionals() + { + DoRewriteFile("Fragments/small_loop.asm"); + Procedure proc = program.Procedures.Values[0]; + using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwDeadConditionals.txt")) + { + proc.Write(true, fut.TextWriter); + fut.AssertFilesEqual(); + } + Assert.AreEqual(5, proc.ControlGraph.Blocks.Count); + } + + [Test] + public void RwPseudoProcs() + { + DoRewriteFile("Fragments/pseudoprocs.asm"); + Procedure proc = program.Procedures.Values[0]; + using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwPseudoProcs.txt")) + { + proc.Write(true, fut.TextWriter); + fut.AssertFilesEqual(); + } + } + + [Test] + public void RwAddSubCarries() + { + RunTest("Fragments/addsubcarries.asm", "Arch/X86/RwAddSubCarries.txt"); + } + + [Test] + public void RwLongAddSub() + { + RunTest("Fragments/longaddsub.asm", "Arch/X86/RwLongAddSub.txt"); + } + + [Test] + public void RwEnterLeave() + { + RunTest("Fragments/enterleave.asm", "Arch/X86/RwEnterLeave.txt"); + } + + [Test] + public void RwReg00003() + { + RunTest("Fragments/regressions/r00003.asm", "Arch/X86/RwReg00003.txt"); + } + + [Test] + public void RwReg00005() + { + RunTest("Fragments/regressions/r00005.asm", "Arch/X86/RwReg00005.txt"); + } + + [Test] + public void RwSequenceShifts() + { + RunTest("Fragments/sequenceshift.asm", "Arch/X86/RwSequenceShifts.txt"); + } + + [Test] + public void RwLogical() + { + RunTest("Fragments/logical.asm", "Arch/X86/RwLogical.txt"); + } + + [Test] + public void RwNegsNots() + { + RunTest("Fragments/negsnots.asm", "Arch/X86/RwNegsNots.txt"); + } + + [Test] + public void RwFpuArgs() + { + RunTest("Fragments/multiple/fpuArgs.asm", "Arch/X86/RwFpuArgs.txt"); + } + + [Test] + public void RwFpuOps() + { + RunTest("Fragments/fpuops.asm", "Arch/X86/RwFpuOps.txt"); + } + + [Test] + public void RwFpuReversibles() + { + RunTest("Fragments/fpureversibles.asm", "Arch/X86/RwFpuReversibles.txt"); + } + + private void RunTest(string sourceFile, string outputFile) + { + DoRewriteFile(sourceFile); + using (FileUnitTester fut = new FileUnitTester(outputFile)) + { + foreach (Procedure proc in program.Procedures.Values) + { + proc.Write(true, fut.TextWriter); + fut.TextWriter.WriteLine(); + } + fut.AssertFilesEqual(); + } + } + + [Test] + public void RwEvenOdd() + { + RunTest("Fragments/multiple/even_odd.asm", "Arch/X86/RwEvenOdd.txt"); + } + + [Test] + public void RwPushPop() + { + RunTest("Fragments/pushpop.asm", "Arch/X86/RwPushPop.txt"); + } + } +} diff --git a/src/UnitTests/Arch/X86/Rewriter/RewriterTests2.cs b/src/UnitTests/Arch/X86/Rewriter/RewriterTests2.cs new file mode 100644 index 0000000000..c67fd12a8c --- /dev/null +++ b/src/UnitTests/Arch/X86/Rewriter/RewriterTests2.cs @@ -0,0 +1,187 @@ +#region License +/* + * Copyright (C) 1999-2023 John Källén. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#endregion + +using NUnit.Framework; +using Reko.Core; +using Reko.Core.Output; + +namespace Reko.UnitTests.Arch.X86.Rewriter +{ + [TestFixture] + public class RewriterTests2 : RewriterTestBase + { + public RewriterTests2() + { + } + + private void RunTest(string sourceFile, string outputFile) + { + DoRewriteFile(sourceFile); + using (FileUnitTester fut = new FileUnitTester(outputFile)) + { + foreach (Procedure proc in program.Procedures.Values) + proc.Write(true, fut.TextWriter); + + fut.AssertFilesEqual(); + } + } + + [Test] + public void X86Rw_Switch() + { + DoRewriteFile("Fragments/switch.asm"); + using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwSwitch.txt")) + { + program.Procedures.Values[0].Write(false, fut.TextWriter); + } + } + + [Test] + public void X86RwDivideTests() + { + Procedure proc = DoRewrite(@".i86 + mov ebx,32 + mov eax,100 + cdq + idiv ebx + mov cx,[si] + mov ax,[si+2] + mov dx,[si+4] + div cx + ret +"); + using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwDivideTests.txt")) + { + proc.Write(false, fut.TextWriter); + fut.AssertFilesEqual(); + } + } + + [Test] + public void X86Rw_MemOperations() + { + DoRewriteFile("Fragments/memoperations.asm"); + using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwMemOperations.txt")) + { + program.Procedures.Values[0].Write(false, fut.TextWriter); + fut.AssertFilesEqual(); + } + } + + [Test] + public void X86Rw_CallTable() + { + DoRewriteFile("Fragments/multiple/calltables.asm"); + using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwCallTable.txt")) + { + Dumper dump = new Dumper(program); + dump.Dump(new TextFormatter(fut.TextWriter)); + fut.TextWriter.WriteLine(); + program.CallGraph.Write(fut.TextWriter); + + fut.AssertFilesEqual(); + } + } + + [Test] + public void X86Rw_StackVariables() + { + RunTest("Fragments/stackvars.asm", "Arch/X86/RwStackVariables.txt"); + } + + [Test] + public void X86Rw_Duff() + { + RunTest("Fragments/duffs_device.asm", "Arch/X86/RwDuff.txt"); + } + + [Test] + public void X86Rw_Factorial() + { + RunTest("Fragments/factorial.asm", "Arch/X86/RwFactorial.txt"); + } + + [Test] + public void X86Rw_Loopne() + { + RunTest("Fragments/loopne.asm", "Arch/X86/RwLoopne.txt"); + } + + [Test] + public void X86Rw_InterprocedureJump() + { + RunTest("Fragments/multiple/jumpintoproc.asm", "Arch/X86/RwInterprocedureJump.txt"); + } + + [Test] + public void X86Rw_PopNoPop() + { + RunTest("Fragments/multiple/popnopop.asm", "Arch/X86/RwPopNoPop.txt"); + } + + [Test] + public void X86Rw_Multiplication() + { + RunTest("Fragments/multiplication.asm", "Arch/X86/RwMultiplication.txt"); + } + + [Test] + public void X86Rw_StackPointerMessing() + { + RunTest("Fragments/multiple/stackpointermessing.asm", "Arch/X86/RwStackPointerMessing.txt"); + } + + [Test] + public void X86Rw_StringInstructions() + { + RunTest("Fragments/stringinstr.asm", "Arch/X86/RwStringInstructions.txt"); + } + + [Test] + public void X86Rw_TestCondition() + { + RunTest("Fragments/setcc.asm", "Arch/X86/RwTestCondition.txt"); + } + + [Test] + public void X86Rw_CopyFile() + { + RunTest("Fragments/copy_file.asm", "Arch/X86/RwCopyFile.txt"); + } + + [Test] + public void X86Rw_ReadFile() + { + RunTest("Fragments/multiple/read_file.asm", "Arch/X86/RwReadFile.txt"); + } + + [Test] + public void X86Rw_ProcIsolation() + { + RunTest("Fragments/multiple/procisolation.asm", "Arch/X86/RwProcIsolation.txt"); + } + + [Test] + public void X86Rw_IntraSegmentFarCall() + { + RunTest("Fragments/multiple/intrasegmentfarcall.asm", "Arch/X86/RwIntraSegmentFarCall.txt"); + } + } +} diff --git a/src/UnitTests/Arch/X86/X86Rewriter_16bitTests.cs b/src/UnitTests/Arch/X86/Rewriter/X86Rewriter_16bitTests.cs similarity index 99% rename from src/UnitTests/Arch/X86/X86Rewriter_16bitTests.cs rename to src/UnitTests/Arch/X86/Rewriter/X86Rewriter_16bitTests.cs index 7b42f6e39f..3bd83da0fa 100644 --- a/src/UnitTests/Arch/X86/X86Rewriter_16bitTests.cs +++ b/src/UnitTests/Arch/X86/Rewriter/X86Rewriter_16bitTests.cs @@ -9,7 +9,7 @@ using System.Text; using System.Threading.Tasks; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Rewriter { [TestFixture] public class X86Rewriter_16bitTests : Arch.RewriterTestBase @@ -418,8 +418,8 @@ public void X86rw_lahf() AssertCode( "0|L--|0C00:0000(1): 1 instructions", "1|L--|ah = SCZOP"); - } - + } + [Test] public void X86rw_lea() { diff --git a/src/UnitTests/Arch/X86/X86RewriterTests.cs b/src/UnitTests/Arch/X86/Rewriter/X86Rewriter_32bitTests.cs similarity index 99% rename from src/UnitTests/Arch/X86/X86RewriterTests.cs rename to src/UnitTests/Arch/X86/Rewriter/X86Rewriter_32bitTests.cs index 4f19696cbf..d5a0748262 100644 --- a/src/UnitTests/Arch/X86/X86RewriterTests.cs +++ b/src/UnitTests/Arch/X86/Rewriter/X86Rewriter_32bitTests.cs @@ -30,28 +30,22 @@ using System.ComponentModel.Design; using System.Linq; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Rewriter { [TestFixture] - partial class X86RewriterTests : Arch.RewriterTestBase + partial class X86Rewriter_32bitTests : Arch.RewriterTestBase { private readonly IntelArchitecture arch32; - private readonly IntelArchitecture arch64; - private readonly Address baseAddr16; private readonly Address baseAddr32; - private readonly Address baseAddr64; private IntelArchitecture arch; private Address baseAddr; private ServiceContainer sc; - private RewriterHost host; - public X86RewriterTests() + public X86Rewriter_32bitTests() { var sc = CreateServiceContainer(); arch32 = new X86ArchitectureFlat32(sc, "x86-protected-32", new Dictionary()); - arch64 = new X86ArchitectureFlat64(sc, "x86-protected-64", new Dictionary()); baseAddr32 = Address.Ptr32(0x10000000); - baseAddr64 = Address.Ptr64(0x140000000ul); } public override IProcessorArchitecture Architecture => arch; @@ -70,7 +64,6 @@ private X86Assembler Create32bitAssembler() arch = arch32; baseAddr = baseAddr32; var asm = new X86Assembler(arch, baseAddr32, new List()); - host = new RewriterHost(arch, asm.ImportReferences); return asm; } @@ -85,7 +78,6 @@ private void Run32bitTest(string hexBytes) { arch = arch32; Given_MemoryArea(new ByteMemoryArea(baseAddr32, BytePattern.FromHexBytes(hexBytes))); - host = new RewriterHost(null); } @@ -123,7 +115,7 @@ public void X86Rw_crc32() "1|L--|edi = __crc32(edi, ebp)"); } - [Test] + [Test] public void X86rw_Neg_mem() { Run32bitTest("F719"); // neg dword ptr [ecx] @@ -312,7 +304,7 @@ public void X86rw_rol_Eb() Run32bitTest("C0C0C0"); AssertCode( "0|L--|10000000(3): 3 instructions", - "1|L--|v3 = (al & 1<8> << 8<8> - 0xC0<8>) != 0<8>", + "1|L--|v3 = (al & 1<8> << 8<8> - 0xC0<8>) != 0<8>", "2|L--|al = __rol(al, 0xC0<8>)", "3|L--|C = v3"); } @@ -515,7 +507,7 @@ public void X86rw_more_xmm() "1|L--|xmm0 = __pshuf(xmm0, xmm0, 0<8>)"); } - + [Test] public void X86rw_PIC_idiom() @@ -2309,7 +2301,7 @@ public void X86Rw_lmsw() } [Test] - public void X86Rw_cmpxchg8b() + public void X86Rw_cmpxchg8b() { Run32bitTest("0FC70F"); // cmpxchg8b qword ptr [edi] AssertCode( @@ -2490,9 +2482,9 @@ public void X86Rw_fsubr() "1|L--|ST[Top:real64] = CONVERT(Mem0[ebp - 0x88<32>:real32], real32, real64) - ST[Top:real64]"); } - - + + [Test] public void X86Rw_adcx() diff --git a/src/UnitTests/Arch/X86/X86Rewriter_64bitTests.cs b/src/UnitTests/Arch/X86/Rewriter/X86Rewriter_64bitTests.cs similarity index 99% rename from src/UnitTests/Arch/X86/X86Rewriter_64bitTests.cs rename to src/UnitTests/Arch/X86/Rewriter/X86Rewriter_64bitTests.cs index d1bdd5fde7..3686a60f4a 100644 --- a/src/UnitTests/Arch/X86/X86Rewriter_64bitTests.cs +++ b/src/UnitTests/Arch/X86/Rewriter/X86Rewriter_64bitTests.cs @@ -23,7 +23,7 @@ using Reko.Core; using System.Collections.Generic; -namespace Reko.UnitTests.Arch.X86 +namespace Reko.UnitTests.Arch.X86.Rewriter { [TestFixture] public class X86Rewriter_64bitTests : Arch.RewriterTestBase diff --git a/src/UnitTests/Arch/X86/RewriterTests.cs b/src/UnitTests/Arch/X86/RewriterTests.cs deleted file mode 100644 index c330794fce..0000000000 --- a/src/UnitTests/Arch/X86/RewriterTests.cs +++ /dev/null @@ -1,317 +0,0 @@ -#region License -/* - * Copyright (C) 1999-2023 John Källén. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#endregion - -using Moq; -using NUnit.Framework; -using Reko.Arch.X86; -using Reko.Arch.X86.Assembler; -using Reko.Core; -using Reko.Core.Assemblers; -using Reko.Core.Code; -using Reko.Core.Configuration; -using Reko.Core.Loading; -using Reko.Core.Serialization; -using Reko.Core.Services; -using Reko.Environments.Msdos; -using Reko.Loading; -using Reko.Scanning; -using Reko.Services; -using Reko.UnitTests.Mocks; -using System.Collections.Generic; -using System.ComponentModel.Design; -using System.IO; - -namespace Reko.UnitTests.Arch.X86 -{ - public class RewriterTestBase - { - private ServiceContainer sc; - private string configFile; - protected IAssembler asm; - protected Program program; - protected Scanner scanner; - protected Address baseAddress; - - public RewriterTestBase() - { - baseAddress = Address.SegPtr(0x0C00, 0); - } - - [SetUp] - public void SetUp() - { - sc = new ServiceContainer(); - sc.AddService(new UnitTestGenerationService(sc)); - sc.AddService(new FileSystemServiceImpl()); - var arch = new X86ArchitectureReal(sc, "x86-real-16", new Dictionary()); - program = new Program() { Architecture = arch }; - asm = new X86TextAssembler(arch); - configFile = null; - } - - public string ConfigFile - { - get { return configFile; } - set { configFile = value; } - } - - protected Procedure DoRewrite(string code) - { - program = asm.AssembleFragment(baseAddress, code); - program.Platform = new MsdosPlatform(sc, program.Architecture); - DoRewriteCore(); - return program.Procedures.Values[0]; - } - - private void DoRewriteCore() - { - var cfgSvc = new Mock(); - var env = new Mock(); - var tlSvc = new Mock(); - var eventListener = new FakeDecompilerEventListener(); - cfgSvc.Setup(c => c.GetEnvironment("ms-dos")).Returns(env.Object); - env.Setup(e => e.TypeLibraries).Returns(new List()); - env.Setup(e => e.CharacteristicsLibraries).Returns(new List()); - sc.AddService(new FakeDecompiledFileService()); - sc.AddService(eventListener); - sc.AddService(eventListener); - sc.AddService(cfgSvc.Object); - sc.AddService(tlSvc.Object); - - Project project = LoadProject(); - project.Programs.Add(this.program); - scanner = new Scanner( - this.program, - project.LoadedMetadata, - new DynamicLinker(project, this.program, eventListener), - sc); - var ep = ImageSymbol.Procedure(this.program.Architecture, baseAddress); - this.program.EntryPoints.Add(ep.Address, ep); - var program = project.Programs[0]; - foreach (var sp in program.User.Procedures.Values) - { - scanner.EnqueueUserProcedure(program.Architecture, sp); - } - scanner.ScanImage(); - } - - private Project LoadProject() - { - Project project = null; - if (configFile != null) - { - var absFile = FileUnitTester.MapTestPath(configFile); - var fsSvc = sc.RequireService(); - using Stream stm = fsSvc.CreateFileStream(absFile, FileMode.Open, FileAccess.Read, FileShare.Read); - project = new ProjectLoader( - null, - new Loader(sc), - ImageLocation.FromUri(absFile), - new FakeDecompilerEventListener()) - .LoadProject(stm); - } - else - { - project = new Project(); - } - return project; - } - - protected void DoRewriteFile(string relativePath) - { - using (var stm = new StreamReader(FileUnitTester.MapTestPath(relativePath))) - { - var lr = asm.Assemble(baseAddress, stm); - program.SegmentMap = lr.SegmentMap; - program.ImageMap = lr.ImageMap; - program.Platform = lr.Platform ?? new MsdosPlatform(sc, lr.Architecture); - } - DoRewriteCore(); - } - } - - /// - /// Unit Tests for the Intel code rewriter. - /// - - [TestFixture] - public class RewriterTests : RewriterTestBase - { - [Test] - public void RwSimpleTest() - { - DoRewrite( - @" .i86 - mov ax,0x0000 - mov cx,0x10 - add ax,cx - ret -"); - - Assert.AreEqual(1, program.Procedures.Count ); - Procedure proc = program.Procedures.Values[0]; - Assert.AreEqual(3, proc.ControlGraph.Blocks.Count); // Entry, code, Exit - - Block block = new List(proc.ControlGraph.Successors(proc.EntryBlock))[0]; - Assert.AreEqual(5, block.Statements.Count); - Assignment instr1 = (Assignment) block.Statements[0].Instruction; - Assert.AreEqual("ax = 0<16>", block.Statements[0].Instruction.ToString()); - - Assert.AreSame(new List(proc.ControlGraph.Successors(block))[0], proc.ExitBlock); - } - - [Test] - public void X86Rw_real_IfTest() - { - Procedure proc = DoRewrite( - @" .i86 - cmp bx,ax - jnz not_eq - - mov cx,3 - jmp join -not_eq: - mov cx,2 -join: - ret -"); - Assert.AreEqual(6, proc.ControlGraph.Blocks.Count); - StringWriter sb = new StringWriter(); - proc.Write(true, sb); - } - - [Test] - public void RwDeadConditionals() - { - DoRewriteFile("Fragments/small_loop.asm"); - Procedure proc = program.Procedures.Values[0]; - using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwDeadConditionals.txt")) - { - proc.Write(true, fut.TextWriter); - fut.AssertFilesEqual(); - } - Assert.AreEqual(5, proc.ControlGraph.Blocks.Count); - } - - [Test] - public void RwPseudoProcs() - { - DoRewriteFile("Fragments/pseudoprocs.asm"); - Procedure proc = program.Procedures.Values[0]; - using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwPseudoProcs.txt")) - { - proc.Write(true, fut.TextWriter); - fut.AssertFilesEqual(); - } - } - - [Test] - public void RwAddSubCarries() - { - RunTest("Fragments/addsubcarries.asm", "Arch/X86/RwAddSubCarries.txt"); - } - - [Test] - public void RwLongAddSub() - { - RunTest("Fragments/longaddsub.asm", "Arch/X86/RwLongAddSub.txt"); - } - - [Test] - public void RwEnterLeave() - { - RunTest("Fragments/enterleave.asm", "Arch/X86/RwEnterLeave.txt"); - } - - [Test] - public void RwReg00003() - { - RunTest("Fragments/regressions/r00003.asm", "Arch/X86/RwReg00003.txt"); - } - - [Test] - public void RwReg00005() - { - RunTest("Fragments/regressions/r00005.asm", "Arch/X86/RwReg00005.txt"); - } - - [Test] - public void RwSequenceShifts() - { - RunTest("Fragments/sequenceshift.asm", "Arch/X86/RwSequenceShifts.txt"); - } - - [Test] - public void RwLogical() - { - RunTest("Fragments/logical.asm", "Arch/X86/RwLogical.txt"); - } - - [Test] - public void RwNegsNots() - { - RunTest("Fragments/negsnots.asm", "Arch/X86/RwNegsNots.txt"); - } - - [Test] - public void RwFpuArgs() - { - RunTest("Fragments/multiple/fpuArgs.asm", "Arch/X86/RwFpuArgs.txt"); - } - - [Test] - public void RwFpuOps() - { - RunTest("Fragments/fpuops.asm", "Arch/X86/RwFpuOps.txt"); - } - - [Test] - public void RwFpuReversibles() - { - RunTest("Fragments/fpureversibles.asm", "Arch/X86/RwFpuReversibles.txt"); - } - - private void RunTest(string sourceFile, string outputFile) - { - DoRewriteFile(sourceFile); - using (FileUnitTester fut = new FileUnitTester(outputFile)) - { - foreach (Procedure proc in program.Procedures.Values) - { - proc.Write(true, fut.TextWriter); - fut.TextWriter.WriteLine(); - } - fut.AssertFilesEqual(); - } - } - - [Test] - public void RwEvenOdd() - { - RunTest("Fragments/multiple/even_odd.asm", "Arch/X86/RwEvenOdd.txt"); - } - - [Test] - public void RwPushPop() - { - RunTest("Fragments/pushpop.asm", "Arch/X86/RwPushPop.txt"); - } - } -} diff --git a/src/UnitTests/Arch/X86/RewriterTests2.cs b/src/UnitTests/Arch/X86/RewriterTests2.cs deleted file mode 100644 index e86dee531b..0000000000 --- a/src/UnitTests/Arch/X86/RewriterTests2.cs +++ /dev/null @@ -1,187 +0,0 @@ -#region License -/* - * Copyright (C) 1999-2023 John Källén. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#endregion - -using NUnit.Framework; -using Reko.Core; -using Reko.Core.Output; - -namespace Reko.UnitTests.Arch.X86 -{ - [TestFixture] - public class RewriterTests2 : RewriterTestBase - { - public RewriterTests2() - { - } - - private void RunTest(string sourceFile, string outputFile) - { - DoRewriteFile(sourceFile); - using (FileUnitTester fut = new FileUnitTester(outputFile)) - { - foreach (Procedure proc in program.Procedures.Values) - proc.Write(true, fut.TextWriter); - - fut.AssertFilesEqual(); - } - } - - [Test] - public void X86Rw_Switch() - { - DoRewriteFile("Fragments/switch.asm"); - using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwSwitch.txt")) - { - program.Procedures.Values[0].Write(false, fut.TextWriter); - } - } - - [Test] - public void X86RwDivideTests() - { - Procedure proc = DoRewrite(@".i86 - mov ebx,32 - mov eax,100 - cdq - idiv ebx - mov cx,[si] - mov ax,[si+2] - mov dx,[si+4] - div cx - ret -"); - using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwDivideTests.txt")) - { - proc.Write(false, fut.TextWriter); - fut.AssertFilesEqual(); - } - } - - [Test] - public void X86Rw_MemOperations() - { - DoRewriteFile("Fragments/memoperations.asm"); - using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwMemOperations.txt")) - { - program.Procedures.Values[0].Write(false, fut.TextWriter); - fut.AssertFilesEqual(); - } - } - - [Test] - public void X86Rw_CallTable() - { - DoRewriteFile("Fragments/multiple/calltables.asm"); - using (FileUnitTester fut = new FileUnitTester("Arch/X86/RwCallTable.txt")) - { - Dumper dump = new Dumper(program); - dump.Dump(new TextFormatter(fut.TextWriter)); - fut.TextWriter.WriteLine(); - program.CallGraph.Write(fut.TextWriter); - - fut.AssertFilesEqual(); - } - } - - [Test] - public void X86Rw_StackVariables() - { - RunTest("Fragments/stackvars.asm", "Arch/X86/RwStackVariables.txt"); - } - - [Test] - public void X86Rw_Duff() - { - RunTest("Fragments/duffs_device.asm", "Arch/X86/RwDuff.txt"); - } - - [Test] - public void X86Rw_Factorial() - { - RunTest("Fragments/factorial.asm", "Arch/X86/RwFactorial.txt"); - } - - [Test] - public void X86Rw_Loopne() - { - RunTest("Fragments/loopne.asm", "Arch/X86/RwLoopne.txt"); - } - - [Test] - public void X86Rw_InterprocedureJump() - { - RunTest("Fragments/multiple/jumpintoproc.asm", "Arch/X86/RwInterprocedureJump.txt"); - } - - [Test] - public void X86Rw_PopNoPop() - { - RunTest("Fragments/multiple/popnopop.asm", "Arch/X86/RwPopNoPop.txt"); - } - - [Test] - public void X86Rw_Multiplication() - { - RunTest("Fragments/multiplication.asm", "Arch/X86/RwMultiplication.txt"); - } - - [Test] - public void X86Rw_StackPointerMessing() - { - RunTest("Fragments/multiple/stackpointermessing.asm", "Arch/X86/RwStackPointerMessing.txt"); - } - - [Test] - public void X86Rw_StringInstructions() - { - RunTest("Fragments/stringinstr.asm", "Arch/X86/RwStringInstructions.txt"); - } - - [Test] - public void X86Rw_TestCondition() - { - RunTest("Fragments/setcc.asm", "Arch/X86/RwTestCondition.txt"); - } - - [Test] - public void X86Rw_CopyFile() - { - RunTest("Fragments/copy_file.asm", "Arch/X86/RwCopyFile.txt"); - } - - [Test] - public void X86Rw_ReadFile() - { - RunTest("Fragments/multiple/read_file.asm", "Arch/X86/RwReadFile.txt"); - } - - [Test] - public void X86Rw_ProcIsolation() - { - RunTest("Fragments/multiple/procisolation.asm", "Arch/X86/RwProcIsolation.txt"); - } - - [Test] - public void X86Rw_IntraSegmentFarCall() - { - RunTest("Fragments/multiple/intrasegmentfarcall.asm", "Arch/X86/RwIntraSegmentFarCall.txt"); - } - } -}