diff options
author | iximeow <me@iximeow.net> | 2021-08-21 17:10:39 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2021-08-21 19:20:41 -0700 |
commit | 0a39607d690755c5f7f7462677fb75580946be2c (patch) | |
tree | ed23871a4c0d7ee722f766eb62230cd959879fd0 | |
parent | 4016cd901ffd6f3a0d93330e734f04617f960666 (diff) |
add description reporting for segment prefixes and opcodes for 32-bit and 16-bit
-rw-r--r-- | src/long_mode/mod.rs | 10 | ||||
-rw-r--r-- | src/protected_mode/mod.rs | 78 | ||||
-rw-r--r-- | src/real_mode/mod.rs | 130 |
3 files changed, 206 insertions, 12 deletions
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 228efee..111ba69 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -7486,10 +7486,12 @@ fn read_with_annotations< .with_id(words.offset() as u32 * 8 - 9) ); } - sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { - desc: InnerDescription::Opcode(opc), - id: words.offset() as u32 * 8 - 8, - }); + if opc != Opcode::Invalid { + sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::Opcode(opc), + id: words.offset() as u32 * 8 - 8, + }); + } sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { desc: InnerDescription::OperandCode(record.1), id: words.offset() as u32 * 8 - 8 + 1, diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index 572513d..20125ca 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -5802,7 +5802,11 @@ fn read_sib< } #[allow(non_snake_case)] -fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +fn read_M_16bit< + T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>, + S: DescriptionSink<FieldDescription> +>(words: &mut T, instr: &mut Instruction, modrm: u8, sink: &mut S) -> Result<OperandSpec, DecodeError> { + let modrm_start = words.offset() as u32 * 8 - 8; let modbits = modrm >> 6; let mmm = modrm & 7; if modbits == 0b00 && mmm == 0b110 { @@ -5842,6 +5846,12 @@ fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpea } match modbits { 0b00 => { + sink.record( + modrm_start + 6, + modrm_start + 7, + InnerDescription::Misc("mmm selects a dereference with no displacement (mod bits: 00)") + .with_id(modrm_start + 0) + ); if mmm > 3 { Ok(OperandSpec::Deref) } else { @@ -5849,7 +5859,21 @@ fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpea } }, 0b01 => { + let disp_start = words.offset() as u32 * 8; instr.disp = read_num(words, 1)? as i8 as i32 as u32; + let disp_end = words.offset() as u32 * 8; + sink.record( + modrm_start + 6, + modrm_start + 7, + InnerDescription::Misc("mmm selects a dereference with 8-bit displacement (mod bits: 01)") + .with_id(modrm_start + 0) + ); + sink.record( + disp_start, + disp_end - 1, + InnerDescription::Number("displacement", instr.disp as i64) + .with_id(disp_start + 3) + ); if mmm > 3 { if instr.disp != 0 { Ok(OperandSpec::RegDisp) @@ -5865,7 +5889,21 @@ fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpea } }, 0b10 => { + let disp_start = words.offset() as u32 * 8; instr.disp = read_num(words, 2)? as i16 as i32 as u32; + let disp_end = words.offset() as u32 * 8; + sink.record( + modrm_start + 6, + modrm_start + 7, + InnerDescription::Misc("mmm selects a dereference with 16-bit displacement (mod bits: 10)") + .with_id(modrm_start + 0) + ); + sink.record( + disp_start, + disp_end - 1, + InnerDescription::Number("displacement", instr.disp as i64) + .with_id(disp_start + 3) + ); if mmm > 3 { if instr.disp != 0 { Ok(OperandSpec::RegDisp) @@ -5894,7 +5932,7 @@ fn read_M< let modrm_start = words.offset() as u32 * 8 - 8; if instr.prefixes.address_size() { - return read_M_16bit(words, instr, modrm); + return read_M_16bit(words, instr, modrm, sink); } instr.regs[1].bank = RegisterBank::D; let modbits = modrm >> 6; @@ -7396,7 +7434,7 @@ fn read_with_annotations< let record: OpcodeRecord = loop { let record = next_rec; - if let Interpretation::Instruction(_) = record.0 { + if let Interpretation::Instruction(opc) = record.0 { if words.offset() > 1 { sink.record( words.offset() as u32 * 8 - 8 - 1, words.offset() as u32 * 8 - 8 - 1, @@ -7404,6 +7442,16 @@ fn read_with_annotations< .with_id(words.offset() as u32 * 8 - 9) ); } + if opc != Opcode::Invalid { + sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::Opcode(opc), + id: words.offset() as u32 * 8 - 8, + }); + } + sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::OperandCode(record.1), + id: words.offset() as u32 * 8 - 8 + 1, + }); break record; } else { let b = nextb; @@ -7436,21 +7484,45 @@ fn read_with_annotations< }; match b { 0x26 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::ES), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_es(); }, 0x2e => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::CS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_cs(); }, 0x36 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::SS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_ss(); }, 0x3e => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::DS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_ds(); }, 0x64 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::FS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_fs(); }, 0x65 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::GS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_gs(); }, 0x66 => { diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs index 7404195..df0ba07 100644 --- a/src/real_mode/mod.rs +++ b/src/real_mode/mod.rs @@ -5802,7 +5802,11 @@ fn read_sib< } #[allow(non_snake_case)] -fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +fn read_M_16bit< + T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>, + S: DescriptionSink<FieldDescription> +>(words: &mut T, instr: &mut Instruction, modrm: u8, sink: &mut S) -> Result<OperandSpec, DecodeError> { + let modrm_start = words.offset() as u32 * 8 - 8; let modbits = modrm >> 6; let mmm = modrm & 7; if modbits == 0b00 && mmm == 0b110 { @@ -5811,37 +5815,91 @@ fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpea } match mmm { 0b000 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `bx + si`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::bx(); instr.regs[2] = RegSpec::si(); }, 0b001 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `bx + di`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::bx(); instr.regs[2] = RegSpec::di(); }, 0b010 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `bp + si`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::bp(); instr.regs[2] = RegSpec::si(); }, 0b011 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `bp + di`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::bp(); instr.regs[2] = RegSpec::di(); }, 0b100 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `si`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::si(); }, 0b101 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `di`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::di(); }, 0b110 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `bp`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::bp(); }, 0b111 => { + sink.record( + modrm_start + 0, + modrm_start + 2, + InnerDescription::Misc("memory address includes `bx`") + .with_id(modrm_start + 2) + ); instr.regs[1] = RegSpec::bx(); }, _ => { unreachable!("impossible bit pattern"); } } match modbits { 0b00 => { + sink.record( + modrm_start + 6, + modrm_start + 7, + InnerDescription::Misc("mod bits of 00 selects a dereference with no displacement") + .with_id(modrm_start + 0) + ); if mmm > 3 { Ok(OperandSpec::Deref) } else { @@ -5849,7 +5907,21 @@ fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpea } }, 0b01 => { + let disp_start = words.offset() as u32 * 8; instr.disp = read_num(words, 1)? as i8 as i32 as u32; + let disp_end = words.offset() as u32 * 8; + sink.record( + modrm_start + 6, + modrm_start + 7, + InnerDescription::Misc("mod bits of 01 selects a dereference with 8-bit displacement") + .with_id(modrm_start + 0) + ); + sink.record( + disp_start, + disp_end - 1, + InnerDescription::Number("displacement", instr.disp as i64) + .with_id(disp_start + 3) + ); if mmm > 3 { if instr.disp != 0 { Ok(OperandSpec::RegDisp) @@ -5865,7 +5937,21 @@ fn read_M_16bit<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpea } }, 0b10 => { + let disp_start = words.offset() as u32 * 8; instr.disp = read_num(words, 2)? as i16 as i32 as u32; + let disp_end = words.offset() as u32 * 8; + sink.record( + modrm_start + 6, + modrm_start + 7, + InnerDescription::Misc("mod bits of 10 selects a dereference with 16-bit displacement") + .with_id(modrm_start + 0) + ); + sink.record( + disp_start, + disp_end - 1, + InnerDescription::Number("displacement", instr.disp as i64) + .with_id(disp_start + 3) + ); if mmm > 3 { if instr.disp != 0 { Ok(OperandSpec::RegDisp) @@ -5895,7 +5981,7 @@ fn read_M< // by default read M as a 16-bit size address if !instr.prefixes.address_size() { - return read_M_16bit(words, instr, modrm); + return read_M_16bit(words, instr, modrm, sink); } instr.regs[1].bank = RegisterBank::D; let modbits = modrm >> 6; @@ -5948,7 +6034,7 @@ fn read_M< sink.record( modrm_start + 6, modrm_start + 7, - InnerDescription::Misc("memory operand is [reg+disp8] indexed by register selected by `mmm` (mod bits: 01)") + InnerDescription::Misc("memory operand is [reg+disp8] indexed by register(s) selected by `mmm` (mod bits: 01)") .with_id(modrm_start + 0) ); read_num(words, 1)? as i8 as i32 @@ -5956,7 +6042,7 @@ fn read_M< sink.record( modrm_start + 6, modrm_start + 7, - InnerDescription::Misc("memory operand is [reg+disp32] indexed by register selected by `mmm` (mod bits: 10)") + InnerDescription::Misc("memory operand is [reg+disp16] indexed by register(s) selected by `mmm` (mod bits: 10)") .with_id(modrm_start + 0) ); read_num(words, 4)? as i32 @@ -7398,7 +7484,7 @@ fn read_with_annotations< let record: OpcodeRecord = loop { let record = next_rec; - if let Interpretation::Instruction(_) = record.0 { + if let Interpretation::Instruction(opc) = record.0 { if words.offset() > 1 { sink.record( words.offset() as u32 * 8 - 8 - 1, words.offset() as u32 * 8 - 8 - 1, @@ -7406,6 +7492,16 @@ fn read_with_annotations< .with_id(words.offset() as u32 * 8 - 9) ); } + if opc != Opcode::Invalid { + sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::Opcode(opc), + id: words.offset() as u32 * 8 - 8, + }); + } + sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::OperandCode(record.1), + id: words.offset() as u32 * 8 - 8 + 1, + }); break record; } else { let b = nextb; @@ -7438,21 +7534,45 @@ fn read_with_annotations< }; match b { 0x26 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::ES), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_es(); }, 0x2e => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::CS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_cs(); }, 0x36 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::SS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_ss(); }, 0x3e => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::DS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_ds(); }, 0x64 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::FS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_fs(); }, 0x65 => { + sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { + desc: InnerDescription::SegmentPrefix(Segment::GS), + id: words.offset() as u32 * 8 - 16, + }); prefixes.set_gs(); }, 0x66 => { |