From 4b62c495ed60bfef592031a34d799c67e35e0044 Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Thu, 14 Dec 2023 16:41:16 +0100 Subject: [PATCH] add instructions object WIP --- androscalpel/src/instructions.rs | 2961 ++++++++++++++++++++++++++++++ androscalpel/src/lib.rs | 2 + 2 files changed, 2963 insertions(+) create mode 100644 androscalpel/src/instructions.rs diff --git a/androscalpel/src/instructions.rs b/androscalpel/src/instructions.rs new file mode 100644 index 0000000..f147717 --- /dev/null +++ b/androscalpel/src/instructions.rs @@ -0,0 +1,2961 @@ +//! Representation of the instructions. +//! +//! Instruction at a sligthly higher level than +//! + +use crate::{DexString, IdField, IdType, Result}; + +use anyhow::anyhow; +use pyo3::prelude::*; + +/// Waste a cycle. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Nop; + +#[pymethods] +impl Nop { + #[new] + pub fn new() -> Self { + Self + } + + pub fn __str__(&self) -> String { + "nop".into() + } + + pub fn __repr__(&self) -> String { + "Instruction(Nop)".into() + } +} + +/// Move contents of a non object register to another. +/// +/// Can represent several dalvik instructions : +/// +/// move vA, vB +/// move/from16 vAA, vBBBB +/// move/16 vAAAA, vBBBB +/// +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Move { + pub from: u16, + pub to: u16, +} + +#[pymethods] +impl Move { + #[new] + pub fn new(from: u16, to: u16) -> Self { + Self { from, to } + } + + pub fn __str__(&self) -> String { + format!("move {} {}", self.to, self.from) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(Move({}, {}))", self.to, self.from) + } +} + +/// Move contents of a register pair to another. +/// +/// Can represent several dalvik instructions : +/// +/// move-wide vA, vB +/// move-wide/from16 vAA, vBBBB +/// move-wide/16 vAAAA, vBBBB +/// +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MoveWide { + pub from: u16, + pub to: u16, +} + +#[pymethods] +impl MoveWide { + #[new] + pub fn new(from: u16, to: u16) -> Self { + Self { from, to } + } + + pub fn __str__(&self) -> String { + format!("move-wide {} {}", self.to, self.from) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MoveWide({}, {}))", self.to, self.from) + } +} + +/// Move contents of an object bearing register to another. +/// +/// Can represent several dalvik instructions : +/// +/// move-object vA, vB +/// move-object/from16 vAA, vBBBB +/// move-object/16 vAAAA, vBBBB +/// +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MoveObject { + pub from: u16, + pub to: u16, +} + +#[pymethods] +impl MoveObject { + #[new] + pub fn new(from: u16, to: u16) -> Self { + Self { from, to } + } + + pub fn __str__(&self) -> String { + format!("move-object {} {}", self.to, self.from) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MoveObject({}, {}))", self.to, self.from) + } +} + +/// Move the single word non object result of the preciding invoke-kind into a register. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MoveResult { + pub to: u8, +} + +#[pymethods] +impl MoveResult { + #[new] + pub fn new(to: u8) -> Self { + Self { to } + } + + pub fn __str__(&self) -> String { + format!("move-result {}", self.to) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MoveResult({}))", self.to) + } +} + +/// Move the double word non object result of the preciding invoke-kind into a register pair. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MoveResultWide { + pub to: u8, +} + +#[pymethods] +impl MoveResultWide { + #[new] + pub fn new(to: u8) -> Self { + Self { to } + } + + pub fn __str__(&self) -> String { + format!("move-result-wide {}", self.to) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MoveResultWide({}))", self.to) + } +} + +/// Move the just caught exception into a register. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MoveException { + pub to: u8, +} + +#[pymethods] +impl MoveException { + #[new] + pub fn new(to: u8) -> Self { + Self { to } + } + + pub fn __str__(&self) -> String { + format!("move-exception {}", self.to) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MoveException({}))", self.to) + } +} + +/// Move the object result of the preciding invoke-kind or filled-new-array into a register. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MoveResultObject { + pub to: u8, +} + +#[pymethods] +impl MoveResultObject { + #[new] + pub fn new(to: u8) -> Self { + Self { to } + } + + pub fn __str__(&self) -> String { + format!("move-result-object {}", self.to) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MoveResultObject({}))", self.to) + } +} + +/// Return a void method +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ReturnVoid; + +#[pymethods] +impl ReturnVoid { + #[new] + pub fn new() -> Self { + Self + } + + pub fn __str__(&self) -> String { + "return-void".into() + } + + pub fn __repr__(&self) -> String { + "Instruction(ReturnVoid)".into() + } +} + +/// Return the 32 bits non object value from the method. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Return { + pub reg: u8, +} + +#[pymethods] +impl Return { + #[new] + pub fn new(reg: u8) -> Self { + Self { reg } + } + + pub fn __str__(&self) -> String { + format!("return {}", self.reg) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(Return({}))", self.reg) + } +} + +/// Return the 64 bits non object value from the method. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ReturnWide { + pub reg: u8, +} + +#[pymethods] +impl ReturnWide { + #[new] + pub fn new(reg: u8) -> Self { + Self { reg } + } + + pub fn __str__(&self) -> String { + format!("return-wide {}", self.reg) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ReturnWide({}))", self.reg) + } +} + +/// Return the object value from the method. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ReturnObject { + pub reg: u8, +} + +#[pymethods] +impl ReturnObject { + #[new] + pub fn new(reg: u8) -> Self { + Self { reg } + } + + pub fn __str__(&self) -> String { + format!("return-object {}", self.reg) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ReturnObject({}))", self.reg) + } +} + +/// Move a literal to a register. +/// +/// Can represent several dalvik instructions : +/// +/// const/4 vA #+B +/// const/16 vAA #+BBBB +/// const vAA #+BBBBBBBB +/// const/high 16 vAA #+BBBB0000 +/// +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Const { + pub reg: u8, + pub lit: i32, +} + +#[pymethods] +impl Const { + #[new] + pub fn new(reg: u8, lit: i32) -> Self { + Self { reg, lit } + } + + pub fn __str__(&self) -> String { + format!("const {} {}", self.reg, self.lit) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(Const({}, {}))", self.reg, self.lit) + } +} + +/// Move a literal to a register pair (64bits). +/// +/// Can represent several dalvik instructions : +/// +/// const-wide/16 vAA #+BBBB +/// const-wide/32 vAA #+BBBBBBBB +/// const-wide vAA #+BBBBBBBBBBBBBBBB +/// const-wide/hight 16 vAA #+BBBB000000000000 +/// +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ConstWide { + pub reg: u8, + pub lit: i64, +} + +#[pymethods] +impl ConstWide { + #[new] + pub fn new(reg: u8, lit: i64) -> Self { + Self { reg, lit } + } + + pub fn __str__(&self) -> String { + format!("const-wide {} {}", self.reg, self.lit) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ConstWide({}, {}))", self.reg, self.lit) + } +} + +/// Move a reference to a string in a register. +/// +/// Can represent several dalvik instructions : +/// +/// const-string vAA string@BBBB +/// const-string/jumbo vAA string@BBBBBBBB +/// +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstString { + pub reg: u8, + pub lit: DexString, +} + +#[pymethods] +impl ConstString { + #[new] + pub fn new(reg: u8, lit: DexString) -> Self { + Self { reg, lit } + } + + pub fn __str__(&self) -> String { + format!("const-string {} \"{}\"", self.reg, self.lit.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ConstString({}, {}))", + self.reg, + self.lit.__repr__() + ) + } +} + +/// Move a reference to a class in a register. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstClass { + pub reg: u8, + pub lit: IdType, +} + +#[pymethods] +impl ConstClass { + #[new] + pub fn new(reg: u8, lit: IdType) -> Self { + Self { reg, lit } + } + + pub fn __str__(&self) -> String { + format!("const-class {} \"{}\"", self.reg, self.lit.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(ConstClass({}, {}))", + self.reg, + self.lit.__repr__() + ) + } +} + +/// Acquire the monitor for the object in the register. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MonitorEnter { + pub reg: u8, +} + +#[pymethods] +impl MonitorEnter { + #[new] + pub fn new(reg: u8) -> Self { + Self { reg } + } + + pub fn __str__(&self) -> String { + format!("monitor-enter {}", self.reg) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MonitorEnter({}))", self.reg) + } +} + +/// Release the monitor for the object in the register. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MonitorExit { + pub reg: u8, +} + +#[pymethods] +impl MonitorExit { + #[new] + pub fn new(reg: u8) -> Self { + Self { reg } + } + + pub fn __str__(&self) -> String { + format!("monitor-exit {}", self.reg) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(MonitorExit({}))", self.reg) + } +} + +/// Check if the object in the register can be cast to the type. +/// (Raise a `ClassCastException` if not) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CheckCast { + pub reg: u8, + pub lit: IdType, +} + +#[pymethods] +impl CheckCast { + #[new] + pub fn new(reg: u8, lit: IdType) -> Self { + Self { reg, lit } + } + + pub fn __str__(&self) -> String { + format!("check-cast {} {}", self.reg, self.lit.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(CheckCast({}, {}))", + self.reg, + self.lit.__repr__() + ) + } +} + +/// Check if an object if an instance of a type. +/// (put 1 in the dest register if yes, else 0) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InstanceOf { + pub dest: u8, + pub obj: u8, + pub lit: IdType, +} + +#[pymethods] +impl InstanceOf { + #[new] + pub fn new(dest: u8, obj: u8, lit: IdType) -> Self { + Self { dest, obj, lit } + } + + pub fn __str__(&self) -> String { + format!( + "instance-of {} {} {}", + self.dest, + self.obj, + self.lit.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(InstanceOf({}, {}, {}))", + self.dest, + self.obj, + self.lit.__repr__() + ) + } +} + +/// Get the number of item in an array. +/// (put the lenght in the dest register) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ArrayLength { + pub dest: u8, + pub arr: u8, +} + +#[pymethods] +impl ArrayLength { + #[new] + pub fn new(dest: u8, arr: u8) -> Self { + Self { dest, arr } + } + + pub fn __str__(&self) -> String { + format!("array-length{} {}", self.dest, self.arr,) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(ArrayLength({}, {}))", self.dest, self.arr,) + } +} + +/// Construct a new instance of the indicated type and store a reference to it. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NewInstance { + pub reg: u8, + pub lit: IdType, +} + +#[pymethods] +impl NewInstance { + #[new] + pub fn new(reg: u8, lit: IdType) -> Self { + Self { reg, lit } + } + + pub fn __str__(&self) -> String { + format!("new-instance {} {}", self.reg, self.lit.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(NewInstance({}, {}))", + self.reg, + self.lit.__repr__() + ) + } +} + +/// Construct a new array of the indicated type and size in size_reg and store a reference to it. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NewArray { + pub reg: u8, + pub size_reg: u8, + pub lit: IdType, +} + +#[pymethods] +impl NewArray { + #[new] + pub fn new(reg: u8, size_reg: u8, lit: IdType) -> Self { + Self { reg, size_reg, lit } + } + + pub fn __str__(&self) -> String { + format!( + "new-array {} {} {}", + self.reg, + self.size_reg, + self.lit.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(NewArray({}, {}, {}))", + self.reg, + self.size_reg, + self.lit.__repr__() + ) + } +} + +/// Construct a new array of the indicated type and size fill it with the values of the +/// given registers. +/// +/// The elements of the array must fit in 32bits. +/// +/// The registers must either be less to 5 and their number must fit on 4 bits each, or +/// be less than 256, their the number of the smallest must fit on 16 bits and they must +/// be sorted an directly adjascent. +/// +/// The newly created array can be retreived with a move-result-object instruction. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FilledNewArray { + pub type_: IdType, + pub reg_values: Vec, +} + +#[pymethods] +impl FilledNewArray { + #[new] + pub fn new(type_: IdType, reg_values: Vec) -> Result { + let array = Self { type_, reg_values }; + array.sanity_check()?; + Ok(array) + } + + pub fn sanity_check(&self) -> Result<()> { + let mut last = None; + let mut consec = true; + let mut four_bites = true; + let len = self.reg_values.len(); + for r in self.reg_values { + if let Some(last) = last { + if r != last + 1 { + consec = false; + } + } + if r & 0b1111_0000 != 0 { + four_bites = false; + } + last = Some(r); + } + if four_bites && len <= 5 { + Ok(()) + } else if consec && len <= 255 { + Ok(()) + } else { + Err(anyhow!( + "filled-new-array instruction must either use 5 or \ + less register indexed on 4 bites or less than 255 \ + consecutive registers" + )) + } + } + + pub fn __str__(&self) -> String { + let args = if self.reg_values.len() >= 5 { + format!( + "{} .. {}", + self.reg_values[0], + self.reg_values[self.reg_values.len() - 1] + ) + } else { + self.reg_values + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(" ") + }; + format!("filled-new-array {{{}}} {}", args, self.type_.__str__()) + } + + pub fn __repr__(&self) -> String { + let args = if self.reg_values.len() >= 5 { + format!( + "{}, ..., {}", + self.reg_values[0], + self.reg_values[self.reg_values.len() - 1] + ) + } else { + self.reg_values + .iter() + .map(|v| format!("{v}")) + .collect::>() + .join(", ") + }; + format!( + "Instruction(FilledNewArray([{}], {}))", + args, + self.type_.__repr__() + ) + } +} + +// TODO: fill-array-data + +/// Throws the exception in the register. +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Throw { + pub reg: u8, +} + +#[pymethods] +impl Throw { + #[new] + pub fn new(reg: u8) -> Self { + Self { reg } + } + + pub fn __str__(&self) -> String { + format!("throw {}", self.reg) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(Throw({}))", self.reg) + } +} + +/// Jump to the label. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Goto { + pub label: String, +} + +#[pymethods] +impl Goto { + #[new] + pub fn new(label: String) -> Self { + Self { label } + } + + pub fn __str__(&self) -> String { + format!("goto {}", self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(Goto({}))", self.label) + } +} + +// TODO packed-switch + +/// Store the result of the comparison between the registers. +/// +/// - b < c: a = -1 +/// - b == c: a = 0 +/// - b > c : a = 1 +/// - b == c == Nan: a = -1 +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CmpLFLoat { + pub dest: u8, + pub b: u8, + pub c: u8, +} + +#[pymethods] +impl CmpLFLoat { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("cmpl-float {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(CmpLFLoat({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Store the result of the comparison between the registers. +/// +/// - b < c: a = -1 +/// - b == c: a = 0 +/// - b > c : a = 1 +/// - b == c == Nan: a = 1 +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CmpGFLoat { + pub dest: u8, + pub b: u8, + pub c: u8, +} + +#[pymethods] +impl CmpGFLoat { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("cmpg-float {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(CmpGFLoat({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Store the result of the comparison between the registers. +/// +/// - b < c: a = -1 +/// - b == c: a = 0 +/// - b > c : a = 1 +/// - b == c == Nan: a = -1 +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CmpLDouble { + pub dest: u8, + pub b: u8, + pub c: u8, +} + +#[pymethods] +impl CmpLDouble { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("cmpl-double {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(CmpLDouble({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Store the result of the comparison between the registers. +/// +/// - b < c: a = -1 +/// - b == c: a = 0 +/// - b > c : a = 1 +/// - b == c == Nan: a = 1 +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CmpGDouble { + pub dest: u8, + pub b: u8, + pub c: u8, +} + +#[pymethods] +impl CmpGDouble { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("cmpg-double {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(CmpGDouble({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Store the result of the comparison between the registers. +/// +/// - b < c: a = -1 +/// - b == c: a = 0 +/// - b > c : a = 1 +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CmpLong { + pub dest: u8, + pub b: u8, + pub c: u8, +} + +#[pymethods] +impl CmpLong { + #[new] + pub fn new(dest: u8, b: u8, c: u8) -> Self { + Self { dest, b, c } + } + + pub fn __str__(&self) -> String { + format!("cmp-long {} {} {}", self.dest, self.b, self.c) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(CmpLong({}, {}, {}))", + self.dest, self.b, self.c + ) + } +} + +/// Jump to the label if a == b +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfEq { + pub a: u8, + pub b: u8, + pub label: String, +} + +#[pymethods] +impl IfEq { + #[new] + pub fn new(a: u8, b: u8, label: String) -> Result { + let ins = Self { a, b, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-eq uses registers indexed on 4 bits, found {}", + self.a + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "if-eq uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-eq {} {} {}", self.a, self.b, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfEq({}, {}, {}))", self.a, self.b, self.label) + } +} + +/// Jump to the label if a != b +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfNeq { + pub a: u8, + pub b: u8, + pub label: String, +} + +#[pymethods] +impl IfNeq { + #[new] + pub fn new(a: u8, b: u8, label: String) -> Result { + let ins = Self { a, b, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-neq uses registers indexed on 4 bits, found {}", + self.a + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "if-neq uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-neq {} {} {}", self.a, self.b, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfNeq({}, {}, {}))", self.a, self.b, self.label) + } +} + +/// Jump to the label if a < b +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfLt { + pub a: u8, + pub b: u8, + pub label: String, +} + +#[pymethods] +impl IfLt { + #[new] + pub fn new(a: u8, b: u8, label: String) -> Result { + let ins = Self { a, b, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-lt uses registers indexed on 4 bits, found {}", + self.a + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "if-lt uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-lt {} {} {}", self.a, self.b, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfLt({}, {}, {}))", self.a, self.b, self.label) + } +} + +/// Jump to the label if a >= b +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfGe { + pub a: u8, + pub b: u8, + pub label: String, +} + +#[pymethods] +impl IfGe { + #[new] + pub fn new(a: u8, b: u8, label: String) -> Result { + let ins = Self { a, b, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-ge uses registers indexed on 4 bits, found {}", + self.a + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "if-ge uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-ge {} {} {}", self.a, self.b, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfGe({}, {}, {}))", self.a, self.b, self.label) + } +} + +/// Jump to the label if a > b +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfGt { + pub a: u8, + pub b: u8, + pub label: String, +} + +#[pymethods] +impl IfGt { + #[new] + pub fn new(a: u8, b: u8, label: String) -> Result { + let ins = Self { a, b, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-gt uses registers indexed on 4 bits, found {}", + self.a + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "if-gt uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-gt {} {} {}", self.a, self.b, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfGt({}, {}, {}))", self.a, self.b, self.label) + } +} + +/// Jump to the label if a <= b +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfLe { + pub a: u8, + pub b: u8, + pub label: String, +} + +#[pymethods] +impl IfLe { + #[new] + pub fn new(a: u8, b: u8, label: String) -> Result { + let ins = Self { a, b, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-le uses registers indexed on 4 bits, found {}", + self.a + )) + } else if self.b & 0b1111_0000 != 0 { + Err(anyhow!( + "if-le uses registers indexed on 4 bits, found {}", + self.b + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-le {} {} {}", self.a, self.b, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfLe({}, {}, {}))", self.a, self.b, self.label) + } +} + +/// Jump to the label if a == 0 +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfEqZ { + pub a: u8, + pub label: String, +} + +#[pymethods] +impl IfEqZ { + #[new] + pub fn new(a: u8, label: String) -> Result { + let ins = Self { a, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-eqz uses registers indexed on 4 bits, found {}", + self.a + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-eqz {} {}", self.a, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfEqZ({}, {}))", self.a, self.label) + } +} + +/// Jump to the label if a != 0 +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfNeqZ { + pub a: u8, + pub label: String, +} + +#[pymethods] +impl IfNeqZ { + #[new] + pub fn new(a: u8, label: String) -> Result { + let ins = Self { a, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-neq uses registers indexed on 4 bits, found {}", + self.a + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-neq {} {}", self.a, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfNeq({}, {}))", self.a, self.label) + } +} + +/// Jump to the label if a < 0 +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfLtZ { + pub a: u8, + pub label: String, +} + +#[pymethods] +impl IfLtZ { + #[new] + pub fn new(a: u8, label: String) -> Result { + let ins = Self { a, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-lt uses registers indexed on 4 bits, found {}", + self.a + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-lt {} {}", self.a, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfLt({}, {}))", self.a, self.label) + } +} + +/// Jump to the label if a >= 0 +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfGeZ { + pub a: u8, + pub label: String, +} + +#[pymethods] +impl IfGeZ { + #[new] + pub fn new(a: u8, label: String) -> Result { + let ins = Self { a, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-ge uses registers indexed on 4 bits, found {}", + self.a + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-ge {} {}", self.a, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfGe({}, {}))", self.a, self.label) + } +} + +/// Jump to the label if a > 0 +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfGtZ { + pub a: u8, + pub label: String, +} + +#[pymethods] +impl IfGtZ { + #[new] + pub fn new(a: u8, label: String) -> Result { + let ins = Self { a, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-gt uses registers indexed on 4 bits, found {}", + self.a + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-gt {} {}", self.a, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfGt({}, {}))", self.a, self.label) + } +} + +/// Jump to the label if a <= 0 +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IfLeZ { + pub a: u8, + pub label: String, +} + +#[pymethods] +impl IfLeZ { + #[new] + pub fn new(a: u8, label: String) -> Result { + let ins = Self { a, label }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.a & 0b1111_0000 != 0 { + Err(anyhow!( + "if-le uses registers indexed on 4 bits, found {}", + self.a + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("if-le {} {}", self.a, self.label) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(IfLe({}, {}))", self.a, self.label) + } +} + +/// Put the value at arr[idx] in register dest (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AGet { + pub dest: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl AGet { + #[new] + pub fn new(dest: u8, arr: u8, idx: u8) -> Self { + Self { dest, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aget {} {} {}", self.dest, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AGet({}, {}, {}))", + self.dest, self.arr, self.idx + ) + } +} + +/// Put the value at arr[idx] in register pair dest (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AGetWide { + pub dest: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl AGetWide { + #[new] + pub fn new(dest: u8, arr: u8, idx: u8) -> Self { + Self { dest, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aget-wide {} {} {}", self.dest, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AGetWide({}, {}, {}))", + self.dest, self.arr, self.idx + ) + } +} + +/// Put the reference at arr[idx] in register (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AGetObject { + pub dest: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl AGetObject { + #[new] + pub fn new(dest: u8, arr: u8, idx: u8) -> Self { + Self { dest, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aget-object {} {} {}", self.dest, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AGetObject({}, {}, {}))", + self.dest, self.arr, self.idx + ) + } +} + +/// Put the boolean at arr[idx] in register dest (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AGetBoolean { + pub dest: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl AGetBoolean { + #[new] + pub fn new(dest: u8, arr: u8, idx: u8) -> Self { + Self { dest, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aget-boolean {} {} {}", self.dest, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AGetBoolean({}, {}, {}))", + self.dest, self.arr, self.idx + ) + } +} + +/// Put the byte at arr[idx] in register dest (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AGetByte { + pub dest: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl AGetByte { + #[new] + pub fn new(dest: u8, arr: u8, idx: u8) -> Self { + Self { dest, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aget-byte {} {} {}", self.dest, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AGetByte({}, {}, {}))", + self.dest, self.arr, self.idx + ) + } +} + +/// Put the char at arr[idx] in register dest (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AGetChar { + pub dest: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl AGetChar { + #[new] + pub fn new(dest: u8, arr: u8, idx: u8) -> Self { + Self { dest, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aget-char {} {} {}", self.dest, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AGetChar({}, {}, {}))", + self.dest, self.arr, self.idx + ) + } +} + +/// Put the short at arr[idx] in register dest (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AGetShort { + pub dest: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl AGetShort { + #[new] + pub fn new(dest: u8, arr: u8, idx: u8) -> Self { + Self { dest, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aget-short {} {} {}", self.dest, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(AGetShort({}, {}, {}))", + self.dest, self.arr, self.idx + ) + } +} + +/// Put the value of register 'from' in arr[idx] (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct APut { + pub from: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl APut { + #[new] + pub fn new(from: u8, arr: u8, idx: u8) -> Self { + Self { from, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aput {} {} {}", self.from, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(APut({}, {}, {}))", + self.from, self.arr, self.idx + ) + } +} + +/// Put the value of the register pair 'from' in arr[idx] (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct APutWide { + pub from: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl APutWide { + #[new] + pub fn new(from: u8, arr: u8, idx: u8) -> Self { + Self { from, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aput-wide {} {} {}", self.from, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(APutWide({}, {}, {}))", + self.from, self.arr, self.idx + ) + } +} + +/// Put the object reference in 'from' in arr[idx] (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct APutObject { + pub from: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl APutObject { + #[new] + pub fn new(from: u8, arr: u8, idx: u8) -> Self { + Self { from, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aput-object {} {} {}", self.from, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(APutObject({}, {}, {}))", + self.from, self.arr, self.idx + ) + } +} + +/// Put the boolean in 'from' in arr[idx] (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct APutBoolean { + pub from: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl APutBoolean { + #[new] + pub fn new(from: u8, arr: u8, idx: u8) -> Self { + Self { from, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aput-boolean {} {} {}", self.from, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(APutBoolean({}, {}, {}))", + self.from, self.arr, self.idx + ) + } +} + +/// Put the byte in 'from' in arr[idx] (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct APutByte { + pub from: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl APutByte { + #[new] + pub fn new(from: u8, arr: u8, idx: u8) -> Self { + Self { from, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aput-byte {} {} {}", self.from, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(APutByte({}, {}, {}))", + self.from, self.arr, self.idx + ) + } +} + +/// Put the char in 'from' in arr[idx] (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct APutChar { + pub from: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl APutChar { + #[new] + pub fn new(from: u8, arr: u8, idx: u8) -> Self { + Self { from, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aput-char {} {} {}", self.from, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(APutChar({}, {}, {}))", + self.from, self.arr, self.idx + ) + } +} + +/// Put the short in 'from' in arr[idx] (all values are in registers) +#[pyclass] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct APutShort { + pub from: u8, + pub arr: u8, + pub idx: u8, +} + +#[pymethods] +impl APutShort { + #[new] + pub fn new(from: u8, arr: u8, idx: u8) -> Self { + Self { from, arr, idx } + } + + pub fn __str__(&self) -> String { + format!("aput-short {} {} {}", self.from, self.arr, self.idx) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(APutShort({}, {}, {}))", + self.from, self.arr, self.idx + ) + } +} + +/// Put the value in 'to' in the instance field 'field' of 'obj' ('to' and 'obj' are register) +/// +/// The registers 'to' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IGet { + pub to: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IGet { + #[new] + pub fn new(to: u8, obj: u8, field: IdField) -> Result { + let ins = Self { to, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.to & 0b1111_0000 != 0 { + Err(anyhow!( + "iget uses registers indexed on 4 bits, found {}", + self.to + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iget uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("iget {} {} {}", self.to, self.obj, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IGet({}, {}, {}))", + self.to, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the value in the register pair 'to' in the instance field 'field' of 'obj' ('to' +/// and 'obj' are register) +/// +/// The registers 'to' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IGetWide { + pub to: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IGetWide { + #[new] + pub fn new(to: u8, obj: u8, field: IdField) -> Result { + let ins = Self { to, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.to & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-wide uses registers indexed on 4 bits, found {}", + self.to + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-wide uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iget-wide {} {} {}", + self.to, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IGetWide({}, {}, {}))", + self.to, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the object reference 'to' in the instance field 'field' of 'obj' ('to' and 'obj' are register) +/// +/// The registers 'to' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IGetObject { + pub to: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IGetObject { + #[new] + pub fn new(to: u8, obj: u8, field: IdField) -> Result { + let ins = Self { to, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.to & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-object uses registers indexed on 4 bits, found {}", + self.to + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-object uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iget-object {} {} {}", + self.to, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IGetObject({}, {}, {}))", + self.to, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the boolean in 'to' in the instance field 'field' of 'obj' ('to' and 'obj' are register) +/// +/// The registers 'to' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IGetBoolean { + pub to: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IGetBoolean { + #[new] + pub fn new(to: u8, obj: u8, field: IdField) -> Result { + let ins = Self { to, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.to & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-boolean uses registers indexed on 4 bits, found {}", + self.to + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-boolean uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iget-boolean {} {} {}", + self.to, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IGetBoolean({}, {}, {}))", + self.to, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the byte in 'to' in the instance field 'field' of 'obj' ('to' and 'obj' are register) +/// +/// The registers 'to' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IGetByte { + pub to: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IGetByte { + #[new] + pub fn new(to: u8, obj: u8, field: IdField) -> Result { + let ins = Self { to, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.to & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-byte uses registers indexed on 4 bits, found {}", + self.to + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-byte uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iget-byte {} {} {}", + self.to, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IGetByte({}, {}, {}))", + self.to, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the char in 'to' in the instance field 'field' of 'obj' ('to' and 'obj' are register) +/// +/// The registers 'to' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IGetChar { + pub to: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IGetChar { + #[new] + pub fn new(to: u8, obj: u8, field: IdField) -> Result { + let ins = Self { to, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.to & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-char uses registers indexed on 4 bits, found {}", + self.to + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-char uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iget-char {} {} {}", + self.to, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IGetChar({}, {}, {}))", + self.to, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the short in 'to' in the instance field 'field' of 'obj' ('to' and 'obj' are register) +/// +/// The registers 'to' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IGetShort { + pub to: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IGetShort { + #[new] + pub fn new(to: u8, obj: u8, field: IdField) -> Result { + let ins = Self { to, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.to & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-short uses registers indexed on 4 bits, found {}", + self.to + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iget-short uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iget-short {} {} {}", + self.to, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IGetShort({}, {}, {}))", + self.to, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the value in the instance field 'field' of 'obj' in 'from' ('from' and 'obj' are register) +/// +/// The registers 'from' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IPut { + pub from: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IPut { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Result { + let ins = Self { from, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.from & 0b1111_0000 != 0 { + Err(anyhow!( + "iput uses registers indexed on 4 bits, found {}", + self.from + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iput uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!("iput {} {} {}", self.from, self.obj, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IPut({}, {}, {}))", + self.from, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the value in the instance field 'field' of 'obj' in the register pair 'from' +/// ('from' and 'obj' are register) +/// +/// The registers 'from' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IPutWide { + pub from: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IPutWide { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Result { + let ins = Self { from, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.from & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-wide uses registers indexed on 4 bits, found {}", + self.from + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-wide uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iput-wide {} {} {}", + self.from, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IPutWide({}, {}, {}))", + self.from, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the object reference in the instance field 'field' of 'obj' in 'from' ('from' and 'obj' are register) +/// +/// The registers 'from' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IPutObject { + pub from: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IPutObject { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Result { + let ins = Self { from, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.from & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-object uses registers indexed on 4 bits, found {}", + self.from + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-object uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iput-object {} {} {}", + self.from, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IPutObject({}, {}, {}))", + self.from, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the boolean in the instance field 'field' of 'obj' in 'from' ('from' and 'obj' are register) +/// +/// The registers 'from' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IPutBoolean { + pub from: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IPutBoolean { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Result { + let ins = Self { from, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.from & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-boolean uses registers indexed on 4 bits, found {}", + self.from + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-boolean uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iput-boolean {} {} {}", + self.from, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IPutBoolean({}, {}, {}))", + self.from, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the byte in the instance field 'field' of 'obj' in 'from' ('from' and 'obj' are register) +/// +/// The registers 'from' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IPutByte { + pub from: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IPutByte { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Result { + let ins = Self { from, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.from & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-byte uses registers indexed on 4 bits, found {}", + self.from + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-byte uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iput-byte {} {} {}", + self.from, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IPutByte({}, {}, {}))", + self.from, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the char in the instance field 'field' of 'obj' in 'from' ('from' and 'obj' are register) +/// +/// The registers 'from' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IPutChar { + pub from: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IPutChar { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Result { + let ins = Self { from, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.from & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-char uses registers indexed on 4 bits, found {}", + self.from + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-char uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iput-char {} {} {}", + self.from, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IPutChar({}, {}, {}))", + self.from, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the short in the instance field 'field' of 'obj' in 'from' ('from' and 'obj' are register) +/// +/// The registers 'from' and 'obj' are idexed on 4 bits. +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct IPutShort { + pub from: u8, + pub obj: u8, + pub field: IdField, +} + +#[pymethods] +impl IPutShort { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Result { + let ins = Self { from, obj, field }; + ins.sanity_check()?; + Ok(ins) + } + + pub fn sanity_check(&self) -> Result<()> { + if self.from & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-short uses registers indexed on 4 bits, found {}", + self.from + )) + } else if self.obj & 0b1111_0000 != 0 { + Err(anyhow!( + "iput-short uses registers indexed on 4 bits, found {}", + self.obj + )) + } else { + Ok(()) + } + } + + pub fn __str__(&self) -> String { + format!( + "iput-short {} {} {}", + self.from, + self.obj, + self.field.__str__() + ) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(IPutShort({}, {}, {}))", + self.from, + self.obj, + self.field.__repr__() + ) + } +} + +/// Put the value in 'to' in the static field 'field' ('to' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SGet { + pub to: u8, + pub field: IdField, +} + +#[pymethods] +impl SGet { + #[new] + pub fn new(to: u8, field: IdField) -> Self { + Self { to, field } + } + + pub fn __str__(&self) -> String { + format!("sget {} {}", self.to, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!("Instruction(SGet({}, {}))", self.to, self.field.__repr__()) + } +} + +/// Put the value in the register pair 'to' in the static field 'field' ('to' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SGetWide { + pub to: u8, + pub field: IdField, +} + +#[pymethods] +impl SGetWide { + #[new] + pub fn new(to: u8, field: IdField) -> Self { + Self { to, field } + } + + pub fn __str__(&self) -> String { + format!("sget-wide {} {}", self.to, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SGetWide({}, {}))", + self.to, + self.field.__repr__() + ) + } +} + +/// Put the object reference 'to' in the static field 'field' ('to' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SGetObject { + pub to: u8, + pub field: IdField, +} + +#[pymethods] +impl SGetObject { + #[new] + pub fn new(to: u8, field: IdField) -> Self { + Self { to, field } + } + + pub fn __str__(&self) -> String { + format!("sget-object {} {}", self.to, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SGetObject({}, {}))", + self.to, + self.field.__repr__() + ) + } +} + +/// Put the boolean in 'to' in the static field 'field' ('to' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SGetBoolean { + pub to: u8, + pub field: IdField, +} + +#[pymethods] +impl SGetBoolean { + #[new] + pub fn new(to: u8, field: IdField) -> Self { + Self { to, field } + } + + pub fn __str__(&self) -> String { + format!("sget-boolean {} {}", self.to, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SGetBoolean({}, {}))", + self.to, + self.field.__repr__() + ) + } +} + +/// Put the byte in 'to' in the static field 'field' ('to' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SGetByte { + pub to: u8, + pub field: IdField, +} + +#[pymethods] +impl SGetByte { + #[new] + pub fn new(to: u8, field: IdField) -> Self { + Self { to, field } + } + + pub fn __str__(&self) -> String { + format!("sget-byte {} {}", self.to, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SGetByte({}, {}))", + self.to, + self.field.__repr__() + ) + } +} + +/// Put the char in 'to' in the static field 'field' ('to' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SGetChar { + pub to: u8, + pub field: IdField, +} + +#[pymethods] +impl SGetChar { + #[new] + pub fn new(to: u8, field: IdField) -> Self { + Self { to, field } + } + + pub fn __str__(&self) -> String { + format!("sget-char {} {}", self.to, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SGetChar({}, {}))", + self.to, + self.field.__repr__() + ) + } +} + +/// Put the short in 'to' in the static field 'field' ('to' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SGetShort { + pub to: u8, + pub field: IdField, +} + +#[pymethods] +impl SGetShort { + #[new] + pub fn new(to: u8, field: IdField) -> Self { + Self { to, field } + } + + pub fn __str__(&self) -> String { + format!("sget-short {} {}", self.to, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SGetShort({}, {}))", + self.to, + self.field.__repr__() + ) + } +} + +/// Put the value in the static field 'field' in 'from' ('from' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SPut { + pub from: u8, + pub field: IdField, +} + +#[pymethods] +impl SPut { + #[new] + pub fn new(from: u8, obj: u8, field: IdField) -> Self { + Self { from, field } + } + + pub fn __str__(&self) -> String { + format!("sput {} {}", self.from, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SPut({}, {}))", + self.from, + self.field.__repr__() + ) + } +} + +/// Put the value in the static field 'field' in the register pair 'from' +/// ('from' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SPutWide { + pub from: u8, + pub field: IdField, +} + +#[pymethods] +impl SPutWide { + #[new] + pub fn new(from: u8, field: IdField) -> Self { + Self { from, field } + } + + pub fn __str__(&self) -> String { + format!("sput-wide {} {}", self.from, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SPutWide({}, {}))", + self.from, + self.field.__repr__() + ) + } +} + +/// Put the object reference in the static field 'field' in 'from' ('from' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SPutObject { + pub from: u8, + pub field: IdField, +} + +#[pymethods] +impl SPutObject { + #[new] + pub fn new(from: u8, field: IdField) -> Self { + Self { from, field } + } + + pub fn __str__(&self) -> String { + format!("sput-object {} {}", self.from, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SPutObject({}, {}))", + self.from, + self.field.__repr__() + ) + } +} + +/// Put the boolean in the static field 'field' in 'from' ('from' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SPutBoolean { + pub from: u8, + pub field: IdField, +} + +#[pymethods] +impl SPutBoolean { + #[new] + pub fn new(from: u8, field: IdField) -> Self { + Self { from, field } + } + + pub fn __str__(&self) -> String { + format!("sput-boolean {} {}", self.from, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SPutBoolean({}, {}))", + self.from, + self.field.__repr__() + ) + } +} + +/// Put the byte in the static field 'field' in 'from' ('from' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SPutByte { + pub from: u8, + pub field: IdField, +} + +#[pymethods] +impl SPutByte { + #[new] + pub fn new(from: u8, field: IdField) -> Self { + Self { from, field } + } + + pub fn __str__(&self) -> String { + format!("sput-byte {} {}", self.from, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SPutByte({}, {}))", + self.from, + self.field.__repr__() + ) + } +} + +/// Put the char in the static field 'field' in 'from' ('from' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SPutChar { + pub from: u8, + pub field: IdField, +} + +#[pymethods] +impl SPutChar { + #[new] + pub fn new(from: u8, field: IdField) -> Self { + Self { from, field } + } + + pub fn __str__(&self) -> String { + format!("sput-char {} {}", self.from, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SPutChar({}, {}))", + self.from, + self.field.__repr__() + ) + } +} + +/// Put the short in the static field 'field' in 'from' ('from' is a register) +#[pyclass] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SPutShort { + pub from: u8, + pub field: IdField, +} + +#[pymethods] +impl SPutShort { + #[new] + pub fn new(from: u8, field: IdField) -> Self { + Self { from, field } + } + + pub fn __str__(&self) -> String { + format!("sput-short {} {}", self.from, self.field.__str__()) + } + + pub fn __repr__(&self) -> String { + format!( + "Instruction(SPutShort({}, {}))", + self.from, + self.field.__repr__() + ) + } +} diff --git a/androscalpel/src/lib.rs b/androscalpel/src/lib.rs index 086daec..c999d53 100644 --- a/androscalpel/src/lib.rs +++ b/androscalpel/src/lib.rs @@ -10,6 +10,7 @@ pub mod dex_id; pub mod dex_string; pub mod dex_writer; pub mod field; +pub mod instructions; pub mod method; pub mod method_handle; pub mod scalar; @@ -23,6 +24,7 @@ pub use dex_id::*; pub use dex_string::*; pub use dex_writer::*; pub use field::*; +//pub use instructions::*; pub use method::*; pub use method_handle::*; pub use scalar::*;