diff options
| author | iximeow <me@iximeow.net> | 2019-01-05 15:26:46 -0800 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2020-01-12 16:10:13 -0800 | 
| commit | d8efc7b6fca3e1c6a9ebf0ada6759a927c12558f (patch) | |
| tree | bcb09ad2413fdb2620492d31dd26c04c41a80af7 | |
| parent | a2fdcc2106024e7e9b1b119c9de50242706c9424 (diff) | |
add more test cases, fix movzx support, add 0xf6 opcodes
| -rw-r--r-- | src/lib.rs | 143 | ||||
| -rw-r--r-- | test/test.rs | 7 | 
2 files changed, 142 insertions, 8 deletions
| @@ -224,6 +224,9 @@ impl fmt::Display for Opcode {              &Opcode::DIV => write!(f, "{}", "div"),              &Opcode::IDIV => write!(f, "{}", "idiv"),              &Opcode::CMPXCHG => write!(f, "{}", "cmpxchg"), +            &Opcode::MOVZX_b => write!(f, "{}", "movzx"), +            &Opcode::MOVZX_w => write!(f, "{}", "movzx"), +            &Opcode::MOVSX => write!(f, "{}", "movsx"),              &Opcode::Invalid => write!(f, "{}", "invalid")          }      } @@ -231,6 +234,9 @@ impl fmt::Display for Opcode {  #[derive(Copy, Clone, Debug, Eq, PartialEq)]  pub enum Opcode { +    MOVZX_b, +    MOVZX_w, +    MOVSX,      SAR,      SAL,      SHR, @@ -427,12 +433,42 @@ impl fmt::Display for Instruction {                  write!(f, " {}", x)              }          }; -        match &self.operands[1] { -            &Operand::Nothing => { -                return Ok(()); +        match self.opcode { +            Opcode::MOVZX_b => { +                match &self.operands[1] { +                    &Operand::Nothing => { +                        return Ok(()); +                    }, +                    x @ &Operand::Register(_) => { +                        write!(f, ", {}", x) +                    } +                    x @ _ => { +                        write!(f, ", byte {}", x) +                    } +                }              }, -            x @ &_ => { -                write!(f, ", {}", x) +            Opcode::MOVZX_w => { +                match &self.operands[1] { +                    &Operand::Nothing => { +                        return Ok(()); +                    }, +                    x @ &Operand::Register(_) => { +                        write!(f, ", {}", x) +                    } +                    x @ _ => { +                        write!(f, ", word {}", x) +                    } +                } +            }, +            _ => { +                match &self.operands[1] { +                    &Operand::Nothing => { +                        return Ok(()); +                    }, +                    x @ &_ => { +                        write!(f, ", {}", x) +                    } +                }              }          }      } @@ -440,6 +476,7 @@ impl fmt::Display for Instruction {  #[derive(Copy, Clone, Debug)]  pub enum OperandCode { +    ModRM_0xf6,      ModRM_0xf7,      Gv_Ev_Iv,      Gb_Eb_Ib, @@ -478,6 +515,8 @@ pub enum OperandCode {      Ew_Sw,      Fw,      Gb_Eb, +    Gv_Eb, +    Gv_Ew,      Gv_Ev,      Gv_M,      I_3, @@ -704,6 +743,16 @@ fn read_opcode_0f_map(bytes_iter: &mut Iterator<Item=&u8>, instruction: &mut Ins                      instruction.opcode = Opcode::CMPXCHG;                      Ok(OperandCode::Ev_Gv)                  } +                0xb6 => { +                    instruction.prefixes = prefixes; +                    instruction.opcode = Opcode::MOVZX_b; +                    Ok(OperandCode::Gv_Eb) +                }, +                0xb7 => { +                    instruction.prefixes = prefixes; +                    instruction.opcode = Opcode::MOVZX_w; +                    Ok(OperandCode::Gv_Ew) +                }                  _ => {                      Err(format!("Unknown opcode: 0f{:x}", b))                  } @@ -1192,7 +1241,11 @@ fn read_opcode(bytes_iter: &mut Iterator<Item=&u8>, instruction: &mut Instructio                          instruction.opcode = Opcode::HLT;                          return Ok(OperandCode::Nothing);                      }, -                    0xf6 => { }, +                    0xf6 => { +                        instruction.prefixes = prefixes; +                        instruction.opcode = Opcode::Invalid; +                        return Ok(OperandCode::ModRM_0xf6); +                    },                      0xf7 => {                          instruction.prefixes = prefixes;                          instruction.opcode = Opcode::Invalid; @@ -1581,6 +1634,48 @@ fn read_operands(                  Err(reason) => Err(reason)              }          }, +        OperandCode::ModRM_0xf6 => { +            let opwidth = 1; +            let modrm = bytes_iter.next().unwrap(); +            let (mod_bits, r, m) = octets_of(*modrm); +            match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { +                Ok(()) => { }, +                Err(reason) => { return Err(reason); } +            }; +            match r { +                0 | 1 => { +                    instruction.opcode = Opcode::TEST; +                    match read_imm_signed(bytes_iter, 1, opwidth) { +                        Ok(imm) => { +                            instruction.operands[1] = imm; +                        }, +                        Err(reason) => { return Err(reason); } +                    } +                }, +                2 => { +                    instruction.opcode = Opcode::NOT; +                }, +                3 => { +                    instruction.opcode = Opcode::NEG; +                }, +                4 => { +                    instruction.opcode = Opcode::MUL; +                }, +                5 => { +                    instruction.opcode = Opcode::IMUL; +                }, +                6 => { +                    instruction.opcode = Opcode::DIV; +                }, +                7 => { +                    instruction.opcode = Opcode::IDIV; +                }, +                _ => { +                    unsafe { unreachable_unchecked(); } +                } +            } +            Ok(()) +        },          OperandCode::ModRM_0xf7 => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes);              let modrm = bytes_iter.next().unwrap(); @@ -1743,6 +1838,42 @@ fn read_operands(                  Err(reason) => Err(reason)              }          }, +        OperandCode::Gv_Eb => { +            let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); +            // TODO: ... +            let modrm = bytes_iter.next().unwrap(); +            let (mod_bits, r, m) = octets_of(*modrm); + +            match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[1]) { +                Ok(()) => { +                    instruction.operands[0] = +                        Operand::Register(RegSpec { +                            num: r, +                            bank: width_to_gp_reg_bank(opwidth) +                        }); +                    Ok(()) +                }, +                Err(reason) => Err(reason) +            } +        }, +        OperandCode::Gv_Ew => { +            let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); +            // TODO: ... +            let modrm = bytes_iter.next().unwrap(); +            let (mod_bits, r, m) = octets_of(*modrm); + +            match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, 2, &mut instruction.operands[1]) { +                Ok(()) => { +                    instruction.operands[0] = +                        Operand::Register(RegSpec { +                            num: r + if instruction.prefixes.rex().b() { 0b1000 } else { 0 }, +                            bank: width_to_gp_reg_bank(opwidth) +                        }); +                    Ok(()) +                }, +                Err(reason) => Err(reason) +            } +        },          // TODO: verify M          OperandCode::Gv_Ev | OperandCode::Gv_M => {              let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); diff --git a/test/test.rs b/test/test.rs index c4133e6..83f24f9 100644 --- a/test/test.rs +++ b/test/test.rs @@ -22,7 +22,7 @@ fn test_mov() {          &[0x48, 0x89, 0x43, 0x18]      ).unwrap()), "mov [rbx + 0x18], rax");      assert_eq!(&format!("{}", decode( -        &[0x48, 0xc7, 0x43, 0x10, 0x00, 0x00, 0x00] +        &[0x48, 0xc7, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00]      ).unwrap()), "mov [rbx + 0x10], 0x0");      assert_eq!(&format!("{}", decode(          &[0x49, 0x89, 0x4e, 0x08] @@ -35,10 +35,13 @@ fn test_mov() {      ).unwrap()), "mov [r14 + 0x10], rax");      assert_eq!(&format!("{}", decode(          &[0x4d, 0x0f, 0x43, 0xec, 0x49] -    ).unwrap()), "cmovae r13, r12"); +    ).unwrap()), "cmovnb r13, r12");      assert_eq!(&format!("{}", decode(          &[0x0f, 0xb6, 0x06]      ).unwrap()), "movzx eax, byte [rsi]"); +    assert_eq!(&format!("{}", decode( +        &[0x0f, 0xb7, 0x06] +    ).unwrap()), "movzx eax, word [rsi]");  }  #[test] | 
