use crate::machine::Machine;
use crate::debug::ProgramTracer;
#[test]
fn trace_simple() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xBA, 0x04, 0x00, 0x89, 0xD1, 0x8E, 0xC2, 0xEB, 0x00, 0xC3, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] BA0400 Mov16 dx, 0x0004 ; dx = 0x0004
[085F:0103] 89D1 Mov16 cx, dx ; cx = 0x0004
[085F:0105] 8EC2 Mov16 es, dx ; es = 0x0004
[085F:0107] EB00 JmpShort 0x0109
[085F:0109] C3 Retn ; xref: jump@085F:0107
", res);
}
#[test]
fn trace_unknown_byte() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xC3, 0x00,
];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] C3 Retn
[085F:0101] 00 db 0x00
", res);
}
#[test]
fn trace_unknown_bytes() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xC3, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05,
];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] C3 Retn
[085F:0101] 00 01 02 03 db 0x00, 0x01, 0x02, 0x03
[085F:0105] 04 05 db 0x04, 0x05
", res);
}
#[test]
fn trace_unknown_bytes_fragmented() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0x72, 0x06, 0xEB, 0x01, 0x03, 0xC3, 0x04, 0x05, 0xEB, 0xFB, 0x06, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] 7206 Jc 0x0108
[085F:0102] EB01 JmpShort 0x0105
[085F:0104] 03 db 0x03
[085F:0105] C3 Retn ; xref: jump@085F:0102, jump@085F:0108
[085F:0106] 04 05 db 0x04, 0x05
[085F:0108] EBFB JmpShort 0x0105 ; xref: branch@085F:0100
[085F:010A] 06 db 0x06
", res);
}
#[test]
fn trace_unreferenced_data() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xBA, 0x04, 0x00, 0x89, 0xD1, 0xEB, 0x01, 0x90, 0xC3, 0x40, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
println!("{}", res);
assert_eq!("[085F:0100] BA0400 Mov16 dx, 0x0004 ; dx = 0x0004
[085F:0103] 89D1 Mov16 cx, dx ; cx = 0x0004
[085F:0105] EB01 JmpShort 0x0108
[085F:0107] 90 db 0x90
[085F:0108] C3 Retn ; xref: jump@085F:0105
[085F:0109] 40 db 0x40
", res);
}
#[test]
fn trace_annotates_stosw() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xAB, 0xF3, 0xAB, 0xE4, 0x60, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] AB Stosw ; [es:di] = ax
[085F:0101] F3AB Rep Stosw ; while cx-- > 0 { [es:di] = ax }
[085F:0103] E460 In8 al, 0x60 ; keyboard: input buffer (0x0060)
", res);
}
#[test]
fn trace_sepatate_call_destination_separators() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xB8, 0x01, 0x00, 0xE8, 0x05, 0x00, 0xB8, 0x02, 0x00, 0xEB, 0x04, 0xB8, 0x03, 0x00, 0xC3, 0xCD, 0x20, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] B80100 Mov16 ax, 0x0001 ; ax = 0x0001
[085F:0103] E80500 CallNear 0x010B
[085F:0106] B80200 Mov16 ax, 0x0002 ; ax = 0x0002
[085F:0109] EB04 JmpShort 0x010F
[085F:010B] B80300 Mov16 ax, 0x0003 ; xref: call@085F:0103; ax = 0x0003
[085F:010E] C3 Retn
[085F:010F] CD20 Int 0x20 ; xref: jump@085F:0109; dos: terminate program with return code 0 | dirty all regs
", res);
}
#[test]
fn trace_virtual_memory() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0x2E, 0xA3, 0x02, 0x02, 0x2E, 0xA1, 0x02, 0x02, 0x2E, 0xA2, 0x05, 0x02, 0x2E, 0xA0, 0x05, 0x02, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] 2EA30202 Mov16 word [cs:0x0202], ax
[085F:0104] 2EA10202 Mov16 ax, word [cs:0x0202]
[085F:0108] 2EA20502 Mov8 byte [cs:0x0205], al
[085F:010C] 2EA00502 Mov8 al, byte [cs:0x0205]
[085F:0202] ?? ?? dw ???? ; xref: word@085F:0100, word@085F:0104
[085F:0205] ?? db ?? ; xref: byte@085F:0108, byte@085F:010C
", res);
}
#[test]
fn trace_break_after_dos_int20() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xCD, 0x20, 0x90, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] CD20 Int 0x20 ; dos: terminate program with return code 0 | dirty all regs
[085F:0102] 90 db 0x90
", res);
}
#[test]
fn trace_break_after_dos_int21_4c() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xB4, 0x4C, 0xCD, 0x21, 0x90, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] B44C Mov8 ah, 0x4C ; ah = 0x4C
[085F:0102] CD21 Int 0x21 ; dos: terminate program with return code in AL | dirty all regs
[085F:0104] 90 db 0x90
", res);
}
#[test]
fn trace_dont_annotate_dirty_regs() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xB8, 0x13, 0x00, 0xCD, 0x10, 0x89, 0xC3, 0xB8, 0x12, 0x00, 0x89, 0xC3, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] B81300 Mov16 ax, 0x0013 ; ax = 0x0013
[085F:0103] CD10 Int 0x10 ; video: set 320x200 VGA mode (0x13) | dirty all regs
[085F:0105] 89C3 Mov16 bx, ax ; bx is dirty
[085F:0107] B81200 Mov16 ax, 0x0012 ; ax = 0x0012
[085F:010A] 89C3 Mov16 bx, ax ; bx = 0x0012
", res);
}
#[test]
fn trace_annotate_int() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xB8, 0x03, 0x00, 0xCD, 0x10, 0xB4, 0x4C, 0xCD, 0x21, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] B80300 Mov16 ax, 0x0003 ; ax = 0x0003
[085F:0103] CD10 Int 0x10 ; video: set 80x25 text mode (0x03) | dirty all regs
[085F:0105] B44C Mov8 ah, 0x4C ; ah = 0x4C
[085F:0107] CD21 Int 0x21 ; dos: terminate program with return code in AL | dirty all regs
", res);
}
#[test]
fn trace_annotate_out() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xB8, 0x34, 0x12, 0xBA, 0xC8, 0x03, 0xE6, 0x40, 0xE7, 0x40, 0xEE, 0xEF, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] B83412 Mov16 ax, 0x1234 ; ax = 0x1234
[085F:0103] BAC803 Mov16 dx, 0x03C8 ; dx = 0x03C8
[085F:0106] E640 Out8 0x40, al ; pit: counter 0, counter divisor (0x0040) = 34
[085F:0108] E740 Out16 0x40, ax ; pit: counter 0, counter divisor (0x0040) = 1234
[085F:010A] EE Out8 dx, al ; vga: PEL address write mode (0x03C8) = 34
[085F:010B] EF Out16 dx, ax ; vga: PEL address write mode (0x03C8) = 1234
", res);
}
#[test]
fn trace_annotate_in() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xBA, 0x60, 0x00, 0xEC, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] BA6000 Mov16 dx, 0x0060 ; dx = 0x0060
[085F:0103] EC In8 al, dx ; keyboard: input buffer (0x0060)
", res);
}
#[test]
fn trace_annotate_regset() {
let mut machine = Machine::deterministic();
let code: Vec<u8> = vec![
0xB8, 0x13, 0x00, 0x89, 0xC2, 0x42, 0xFE, 0xC2, 0x88, 0xD3, 0x4B, 0xFE, 0xCB, 0x00, 0xD3, 0x80, 0xC3, 0x05, 0x01, 0xC3, 0x81, 0xC3, 0xF0, 0xFF, 0x83, 0xC3, 0x04, 0x28, 0xD3, 0x80, 0xEB, 0x05, 0x29, 0xC3, 0x81, 0xEB, 0x00, 0x60, 0x83, 0xEB, 0x04, 0x31, 0xC0, 0x30, 0xDB, ];
machine.load_executable(&code);
let mut tracer = ProgramTracer::default();
tracer.trace_execution(&mut machine);
let res = tracer.present_trace(&mut machine);
assert_eq!("[085F:0100] B81300 Mov16 ax, 0x0013 ; ax = 0x0013
[085F:0103] 89C2 Mov16 dx, ax ; dx = 0x0013
[085F:0105] 42 Inc16 dx ; dx = 0x0014
[085F:0106] FEC2 Inc8 dl ; dl = 0x15
[085F:0108] 88D3 Mov8 bl, dl ; bl = 0x15
[085F:010A] 4B Dec16 bx ; bx = 0x0014
[085F:010B] FECB Dec8 bl ; bl = 0x13
[085F:010D] 00D3 Add8 bl, dl ; bl = 0x28
[085F:010F] 80C305 Add8 bl, 0x05 ; bl = 0x2D
[085F:0112] 01C3 Add16 bx, ax ; bx = 0x0040
[085F:0114] 81C3F0FF Add16 bx, 0xFFF0 ; bx = 0x0030
[085F:0118] 83C304 Add16 bx, byte +0x04 ; bx = 0x0034
[085F:011B] 28D3 Sub8 bl, dl ; bl = 0x1F
[085F:011D] 80EB05 Sub8 bl, 0x05 ; bl = 0x1A
[085F:0120] 29C3 Sub16 bx, ax ; bx = 0x0007
[085F:0122] 81EB0060 Sub16 bx, 0x6000 ; bx = 0xA007
[085F:0126] 83EB04 Sub16 bx, byte +0x04 ; bx = 0xA003
[085F:0129] 31C0 Xor16 ax, ax ; ax = 0x0000
[085F:012B] 30DB Xor8 bl, bl ; bl = 0x00
", res);
}