1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use core::{cmp, fmt, mem, ops, ptr, str};
use super::Int;

/// Byte slice representing an opcode.
#[derive(Eq, PartialEq, Hash)]
pub struct OpCode([u8]);
impl OpCode {
	/// Helps reading immediate and displacement values.
	///
	/// # Examples
	///
	/// ```
	/// // mov eax, 0x01010101
	/// let opcode: &lde::OpCode = b"\xB8\x01\x01\x01\x01".into();
	///
	/// // reads the immedate value
	/// let result = opcode.read::<u32>(1);
	///
	/// assert_eq!(result, 0x01010101);
	/// ```
	///
	/// # Panics
	///
	/// Panics if `offset..offset + sizeof(T)` is out of bounds.
	pub fn read<T: Int>(&self, offset: usize) -> T {
		let p = self.0[offset..offset + mem::size_of::<T>()].as_ptr() as *const T;
		unsafe { ptr::read_unaligned(p) }
	}
	/// Helps writing immediate and displacement values.
	///
	/// # Examples
	///
	/// ```
	/// // mov al, 1
	/// let mut opcode = [0xb0, 0x01];
	/// let opcode: &mut lde::OpCode = (&mut opcode).into();
	///
	/// // change the immediate to 0xff
	/// opcode.write(1, 0xff_u8);
	///
	/// assert_eq!(opcode, &[0xb0, 0xff]);
	/// ```
	///
	/// # Panics
	///
	/// Panics if `offset..offset + sizeof(T)` is out of bounds.
	pub fn write<T: Int>(&mut self, offset: usize, val: T) -> &mut OpCode {
		let p = self.0[offset..offset + mem::size_of::<T>()].as_mut_ptr() as *mut T;
		unsafe { ptr::write_unaligned(p, val); }
		self
	}
}
impl<'a, T: AsRef<[u8]> + ?Sized> From<&'a T> for &'a OpCode {
	fn from(bytes: &'a T) -> &'a OpCode {
		unsafe { mem::transmute(bytes.as_ref()) }
	}
}
impl<'a, T: AsMut<[u8]> + ?Sized> From<&'a mut T> for &'a mut OpCode {
	fn from(bytes: &'a mut T) -> &'a mut OpCode {
		unsafe { mem::transmute(bytes.as_mut()) }
	}
}
impl<'a> From<&'a OpCode> for &'a [u8] {
	fn from(opcode: &'a OpCode) -> &'a [u8] {
		&opcode.0
	}
}
impl<'a> From<&'a mut OpCode> for &'a mut [u8] {
	fn from(opcode: &'a mut OpCode) -> &'a mut [u8] {
		&mut opcode.0
	}
}
impl ops::Deref for OpCode {
	type Target = [u8];
	fn deref(&self) -> &[u8] {
		&self.0
	}
}
impl ops::DerefMut for OpCode {
	fn deref_mut(&mut self) -> &mut [u8] {
		&mut self.0
	}
}
impl<T: AsRef<[u8]> + ?Sized> cmp::PartialEq<T> for OpCode {
	fn eq(&self, other: &T) -> bool {
		self.0.eq(other.as_ref())
	}
}
impl fmt::Display for OpCode {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		fmt(f, self)
	}
}
impl fmt::Debug for OpCode {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		fmt(f, self)
	}
}

pub fn fmt(f: &mut fmt::Formatter, bytes: &[u8]) -> fmt::Result {
	let mut space = false;
	for &byte in bytes.iter() {
		if space && f.alternate() {
			f.write_str(" ")?;
		}
		space = true;

		let n1 = byte >> 4;
		let c1 = if n1 < 10 { b'0' + n1 } else { b'A' + (n1 - 10) };
		let n2 = byte & 0xf;
		let c2 = if n2 < 10 { b'0' + n2 } else { b'A' + (n2 - 10) };
		let s = [c1, c2];
		f.write_str(unsafe { str::from_utf8_unchecked(&s) })?;
	}
	Ok(())
}