aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/display.rs19
-rw-r--r--src/lib.rs212
-rw-r--r--test/test.rs17
3 files changed, 248 insertions, 0 deletions
diff --git a/src/display.rs b/src/display.rs
index 6846174..d11c7c5 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -174,6 +174,15 @@ impl <T: std::fmt::Write> Colorize<T> for Operand {
impl fmt::Display for Opcode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
+ &Opcode::CPUID => write!(f, "{}", "cpuid"),
+ &Opcode::UD2 => write!(f, "{}", "ud2"),
+ &Opcode::WBINVD => write!(f, "{}", "wbinvd"),
+ &Opcode::INVD => write!(f, "{}", "invd"),
+ &Opcode::SYSRET => write!(f, "{}", "sysret"),
+ &Opcode::CLTS => write!(f, "{}", "clts"),
+ &Opcode::SYSCALL => write!(f, "{}", "syscall"),
+ &Opcode::LSL => write!(f, "{}", "lsl"),
+ &Opcode::LAR => write!(f, "{}", "lar"),
&Opcode::INC => write!(f, "{}", "inc"),
&Opcode::DEC => write!(f, "{}", "dec"),
&Opcode::HLT => write!(f, "{}", "hlt"),
@@ -406,6 +415,16 @@ impl <T: std::fmt::Write> Colorize<T> for Opcode {
Opcode::CMP |
Opcode::CMPXCHG => { write!(out, "{}", colors.comparison_op(self)) }
+ Opcode::CPUID |
+ Opcode::WBINVD |
+ Opcode::INVD |
+ Opcode::SYSRET |
+ Opcode::CLTS |
+ Opcode::SYSCALL |
+ Opcode::LSL |
+ Opcode::LAR => { write!(out, "{}", colors.platform_op(self)) }
+
+ Opcode::UD2 |
Opcode::Invalid => { write!(out, "{}", colors.invalid_op(self)) }
}
}
diff --git a/src/lib.rs b/src/lib.rs
index f2e19c7..556ed8a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -85,6 +85,16 @@ impl RegSpec {
}
#[inline]
+ pub fn fs() -> RegSpec {
+ RegSpec { bank: RegisterBank::S, num: 3 }
+ }
+
+ #[inline]
+ pub fn gs() -> RegSpec {
+ RegSpec { bank: RegisterBank::S, num: 4 }
+ }
+
+ #[inline]
pub fn rax() -> RegSpec {
RegSpec { bank: RegisterBank::Q, num: 0 }
}
@@ -268,6 +278,15 @@ pub enum Opcode {
SETGE,
SETLE,
SETG,
+ CPUID,
+ UD2,
+ WBINVD,
+ INVD,
+ SYSRET,
+ CLTS,
+ SYSCALL,
+ LSL,
+ LAR,
Invalid
}
#[derive(Debug)]
@@ -427,6 +446,14 @@ impl PrefixRex {
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug)]
pub enum OperandCode {
+ ModRM_0x0f00,
+ ModRM_0x0f01,
+ Rq_Cq_0,
+ Rq_Dq_0,
+ Cq_Rq_0,
+ Dq_Rq_0,
+ FS,
+ GS,
Eb_R0,
ModRM_0xf6,
ModRM_0xf7,
@@ -521,11 +548,79 @@ fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mu
Some(b) => {
*length += 1;
match b {
+ 0x00 => {
+ instruction.prefixes = prefixes;
+ Ok(OperandCode::ModRM_0x0f00)
+ }
+ 0x01 => {
+ instruction.prefixes = prefixes;
+ Ok(OperandCode::ModRM_0x0f00)
+ }
+ 0x02 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::LAR;
+ Ok(OperandCode::Gv_M)
+ }
+ 0x03 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::LSL;
+ Ok(OperandCode::Gv_M)
+ }
+ 0x05 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::SYSCALL;
+ Ok(OperandCode::Nothing)
+ }
+ 0x06 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::CLTS;
+ Ok(OperandCode::Nothing)
+ }
+ 0x07 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::SYSRET;
+ Ok(OperandCode::Nothing)
+ }
+ 0x08 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::INVD;
+ Ok(OperandCode::Nothing)
+ }
+ 0x09 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::WBINVD;
+ Ok(OperandCode::Nothing)
+ }
+ 0x0b => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::UD2;
+ Ok(OperandCode::Nothing)
+ }
0x1f => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::NOP;
Ok(OperandCode::Ev)
},
+ 0x20 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::MOV;
+ Ok(OperandCode::Rq_Cq_0)
+ },
+ 0x21 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::MOV;
+ Ok(OperandCode::Rq_Dq_0)
+ },
+ 0x22 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::MOV;
+ Ok(OperandCode::Cq_Rq_0)
+ },
+ 0x23 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::MOV;
+ Ok(OperandCode::Dq_Rq_0)
+ },
0x40 => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::CMOVO;
@@ -708,6 +803,36 @@ fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mu
][(x & 0xf) as usize];
Ok(OperandCode::Eb_R0)
}
+ 0xa0 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::PUSH;
+ Ok(OperandCode::FS)
+ }
+ 0xa1 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::POP;
+ Ok(OperandCode::GS)
+ }
+ 0xa2 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::CPUID;
+ Ok(OperandCode::Nothing)
+ }
+ 0xa8 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::PUSH;
+ Ok(OperandCode::Nothing)
+ }
+ 0xa9 => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::PUSH;
+ Ok(OperandCode::GS)
+ }
+ 0xae => {
+ instruction.prefixes = prefixes;
+ instruction.opcode = Opcode::PUSH;
+ Ok(OperandCode::GS)
+ }
0xb0 => {
instruction.prefixes = prefixes;
instruction.opcode = Opcode::CMPXCHG;
@@ -2097,6 +2222,93 @@ fn read_operands<T: Iterator<Item=u8>>(
instruction.operands = [Operand::ImmediateI32(offset as i32), Operand::Nothing];
Ok(())
}
+ OperandCode::Rq_Cq_0 => {
+ let opwidth = 8;
+ let modrm = match bytes_iter.next() {
+ Some(b) => b,
+ None => return Err("Out of bytes".to_string())
+ };
+ *length += 1;
+ let (_, mut r, mut m) = octets_of(modrm);
+ if instruction.prefixes.rex().r() {
+ r += 0b1000;
+ }
+ if instruction.prefixes.rex().b() {
+ m += 0b1000;
+ }
+ instruction.operands = [
+ Operand::Register(RegSpec { bank: RegisterBank::Q, num: m }),
+ Operand::Register(RegSpec { bank: RegisterBank::CR, num: r })
+ ];
+ Ok(())
+ }
+ OperandCode::Rq_Dq_0 => {
+ let opwidth = 8;
+ let modrm = match bytes_iter.next() {
+ Some(b) => b,
+ None => return Err("Out of bytes".to_string())
+ };
+ let (_, mut r, mut m) = octets_of(modrm);
+ if instruction.prefixes.rex().r() {
+ r += 0b1000;
+ }
+ if instruction.prefixes.rex().b() {
+ m += 0b1000;
+ }
+ instruction.operands = [
+ Operand::Register(RegSpec { bank: RegisterBank::Q, num: m }),
+ Operand::Register(RegSpec { bank: RegisterBank::DR, num: r })
+ ];
+ Ok(())
+ }
+ OperandCode::Cq_Rq_0 => {
+ let opwidth = 8;
+ let modrm = match bytes_iter.next() {
+ Some(b) => b,
+ None => return Err("Out of bytes".to_string())
+ };
+ *length += 1;
+ let (_, mut r, mut m) = octets_of(modrm);
+ if instruction.prefixes.rex().r() {
+ r += 0b1000;
+ }
+ if instruction.prefixes.rex().b() {
+ m += 0b1000;
+ }
+ instruction.operands = [
+ Operand::Register(RegSpec { bank: RegisterBank::CR, num: r }),
+ Operand::Register(RegSpec { bank: RegisterBank::Q, num: m })
+ ];
+ Ok(())
+ }
+ OperandCode::Dq_Rq_0 => {
+ let opwidth = 8;
+ let modrm = match bytes_iter.next() {
+ Some(b) => b,
+ None => return Err("Out of bytes".to_string())
+ };
+ *length += 1;
+ let (_, mut r, mut m) = octets_of(modrm);
+ if instruction.prefixes.rex().r() {
+ r += 0b1000;
+ }
+ if instruction.prefixes.rex().b() {
+ m += 0b1000;
+ }
+ instruction.operands = [
+ Operand::Register(RegSpec { bank: RegisterBank::DR, num: r }),
+ Operand::Register(RegSpec { bank: RegisterBank::Q, num: m })
+ ];
+ Ok(())
+ }
+ OperandCode::FS => {
+ instruction.operands = [Operand::Register(RegSpec::fs()), Operand::Nothing];
+ Ok(())
+ }
+ OperandCode::GS => {
+ instruction.operands = [Operand::Register(RegSpec::fs()), Operand::Nothing];
+ Ok(())
+ }
OperandCode::Nothing => {
instruction.operands = [Operand::Nothing, Operand::Nothing];
Ok(())
diff --git a/test/test.rs b/test/test.rs
index df94aeb..1e73a2e 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -38,6 +38,23 @@ fn test_display(data: &[u8], expected: &'static str) {
}
#[test]
+fn test_system() {
+ test_display(&[0x45, 0x0f, 0x22, 0xc8], "mov cr9, r8");
+ test_display(&[0x45, 0x0f, 0x20, 0xc8], "mov r8, cr9");
+ test_display(&[0x40, 0x0f, 0x22, 0xc8], "mov cr1, rax");
+ test_display(&[0x0f, 0x22, 0xc8], "mov cr1, rax");
+ test_display(&[0x44, 0x0f, 0x22, 0xcf], "mov cr9, rdi");
+ test_display(&[0x0f, 0x22, 0xcf], "mov cr1, rdi");
+ test_display(&[0x0f, 0x20, 0xc8], "mov rax, cr1");
+
+ test_display(&[0x45, 0x0f, 0x23, 0xc8], "mov dr9, r8");
+ test_display(&[0x45, 0x0f, 0x21, 0xc8], "mov r8, dr9");
+ test_display(&[0x40, 0x0f, 0x23, 0xc8], "mov dr1, rax");
+ test_display(&[0x0f, 0x23, 0xc8], "mov dr1, rax");
+ test_display(&[0x0f, 0x21, 0xc8], "mov rax, dr1");
+}
+
+#[test]
fn test_arithmetic() {
test_display(&[0x81, 0xec, 0x10, 0x03, 0x00, 0x00], "sub esp, 0x310");
}