diff --git a/androscalpel/src/instructions.rs b/androscalpel/src/instructions.rs index d1f7e75..a141920 100644 --- a/androscalpel/src/instructions.rs +++ b/androscalpel/src/instructions.rs @@ -37,398 +37,1208 @@ const U16_MAX_AS_USIZE: usize = u16::MAX as usize; pub enum Instruction { /// Waste a cycle. Nop {}, - Move(Move), - MoveWide(MoveWide), - MoveObject(MoveObject), - MoveResult(MoveResult), - MoveResultWide(MoveResultWide), - MoveException(MoveException), - MoveResultObject(MoveResultObject), - ReturnVoid(ReturnVoid), - Return(Return), - ReturnWide(ReturnWide), - ReturnObject(ReturnObject), - Const(Const), - ConstWide(ConstWide), - ConstString(ConstString), - ConstClass(ConstClass), - MonitorEnter(MonitorEnter), - MonitorExit(MonitorExit), - CheckCast(CheckCast), - InstanceOf(InstanceOf), - ArrayLength(ArrayLength), - NewInstance(NewInstance), - NewArray(NewArray), - FilledNewArray(FilledNewArray), - FillArrayData(FillArrayData), - Throw(Throw), - Goto(Goto), - Switch(Switch), - CmpLFloat(CmpLFloat), - CmpGFloat(CmpGFloat), - CmpLDouble(CmpLDouble), - CmpGDouble(CmpGDouble), - CmpLong(CmpLong), - IfEq(IfEq), - IfNe(IfNe), - IfLt(IfLt), - IfGe(IfGe), - IfGt(IfGt), - IfLe(IfLe), - IfEqZ(IfEqZ), - IfNeZ(IfNeZ), - IfLtZ(IfLtZ), - IfGeZ(IfGeZ), - IfGtZ(IfGtZ), - IfLeZ(IfLeZ), - AGet(AGet), - AGetWide(AGetWide), - AGetObject(AGetObject), - AGetBoolean(AGetBoolean), - AGetByte(AGetByte), - AGetChar(AGetChar), - AGetShort(AGetShort), - APut(APut), - APutWide(APutWide), - APutObject(APutObject), - APutBoolean(APutBoolean), - APutByte(APutByte), - APutChar(APutChar), - APutShort(APutShort), - IGet(IGet), - IGetWide(IGetWide), - IGetObject(IGetObject), - IGetBoolean(IGetBoolean), - IGetByte(IGetByte), - IGetChar(IGetChar), - IGetShort(IGetShort), - IPut(IPut), - IPutWide(IPutWide), - IPutObject(IPutObject), - IPutBoolean(IPutBoolean), - IPutByte(IPutByte), - IPutChar(IPutChar), - IPutShort(IPutShort), - SGet(SGet), - SGetWide(SGetWide), - SGetObject(SGetObject), - SGetBoolean(SGetBoolean), - SGetByte(SGetByte), - SGetChar(SGetChar), - SGetShort(SGetShort), - SPut(SPut), - SPutWide(SPutWide), - SPutObject(SPutObject), - SPutBoolean(SPutBoolean), - SPutByte(SPutByte), - SPutChar(SPutChar), - SPutShort(SPutShort), - InvokeVirtual(InvokeVirtual), - InvokeSuper(InvokeSuper), - InvokeDirect(InvokeDirect), - InvokeStatic(InvokeStatic), - InvokeInterface(InvokeInterface), - NegInt(NegInt), - NotInt(NotInt), - NegLong(NegLong), - NotLong(NotLong), - NegFloat(NegFloat), - NegDouble(NegDouble), - IntToLong(IntToLong), - IntToFloat(IntToFloat), - IntToDouble(IntToDouble), - LongToInt(LongToInt), - LongToFloat(LongToFloat), - LongToDouble(LongToDouble), - FloatToInt(FloatToInt), - FloatToLong(FloatToLong), - FloatToDouble(FloatToDouble), - DoubleToInt(DoubleToInt), - DoubleToLong(DoubleToLong), - DoubleToFloat(DoubleToFloat), - IntToByte(IntToByte), - IntToChar(IntToChar), - IntToShort(IntToShort), - AddInt(AddInt), - SubInt(SubInt), - MulInt(MulInt), - DivInt(DivInt), - RemInt(RemInt), - AndInt(AndInt), - OrInt(OrInt), - XorInt(XorInt), - ShlInt(ShlInt), - ShrInt(ShrInt), - UshrInt(UshrInt), - AddLong(AddLong), - SubLong(SubLong), - MulLong(MulLong), - DivLong(DivLong), - RemLong(RemLong), - AndLong(AndLong), - OrLong(OrLong), - XorLong(XorLong), - ShlLong(ShlLong), - ShrLong(ShrLong), - UshrLong(UshrLong), - AddFloat(AddFloat), - SubFloat(SubFloat), - MulFloat(MulFloat), - DivFloat(DivFloat), - RemFloat(RemFloat), - AddDouble(AddDouble), - SubDouble(SubDouble), - MulDouble(MulDouble), - DivDouble(DivDouble), - RemDouble(RemDouble), - AddInt2Addr(AddInt2Addr), - SubInt2Addr(SubInt2Addr), - MulInt2Addr(MulInt2Addr), - DivInt2Addr(DivInt2Addr), - RemInt2Addr(RemInt2Addr), - AndInt2Addr(AndInt2Addr), - OrInt2Addr(OrInt2Addr), - XorInt2Addr(XorInt2Addr), - ShlInt2Addr(ShlInt2Addr), - ShrInt2Addr(ShrInt2Addr), - UshrInt2Addr(UshrInt2Addr), - AddLong2Addr(AddLong2Addr), - SubLong2Addr(SubLong2Addr), - MulLong2Addr(MulLong2Addr), - DivLong2Addr(DivLong2Addr), - RemLong2Addr(RemLong2Addr), - AndLong2Addr(AndLong2Addr), - OrLong2Addr(OrLong2Addr), - XorLong2Addr(XorLong2Addr), - ShlLong2Addr(ShlLong2Addr), - ShrLong2Addr(ShrLong2Addr), - UshrLong2Addr(UshrLong2Addr), - AddFloat2Addr(AddFloat2Addr), - SubFloat2Addr(SubFloat2Addr), - MulFloat2Addr(MulFloat2Addr), - DivFloat2Addr(DivFloat2Addr), - RemFloat2Addr(RemFloat2Addr), - AddDouble2Addr(AddDouble2Addr), - SubDouble2Addr(SubDouble2Addr), - MulDouble2Addr(MulDouble2Addr), - DivDouble2Addr(DivDouble2Addr), - RemDouble2Addr(RemDouble2Addr), - AddIntLit(AddIntLit), - RsubIntLit(RsubIntLit), - MulIntLit(MulIntLit), - DivIntLit(DivIntLit), - RemIntLit(RemIntLit), - AndIntLit(AndIntLit), - OrIntLit(OrIntLit), - XorIntLit(XorIntLit), - ShlIntLit(ShlIntLit), - ShrIntLit(ShrIntLit), - UshrIntLit(UshrIntLit), - InvokePolymorphic(InvokePolymorphic), - InvokeCustom(InvokeCustom), - ConstMethodHandle(ConstMethodHandle), - ConstMethodType(ConstMethodType), - Try(Try), - Label(Label), + /// 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 + Move { from: u16, to: u16 }, + /// 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 + MoveWide { from: u16, to: u16 }, + /// 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 + MoveObject { from: u16, to: u16 }, + /// Move the single word non object result of the preciding invoke-kind into a register. + MoveResult { to: u8 }, + /// Move the double word non object result of the preciding invoke-kind into a register pair. + MoveResultWide { to: u8 }, + /// Move the just caught exception into a register. + MoveException { to: u8 }, + /// Move the object result of the preciding invoke-kind or filled-new-array into a register. + MoveResultObject { to: u8 }, + /// Return a void method + ReturnVoid {}, + /// Return the 32 bits non object value from the method. + Return { reg: u8 }, + /// Return the 64 bits non object value from the method. + ReturnWide { reg: u8 }, + /// Return the object value from the method. + ReturnObject { reg: u8 }, + /// 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 + Const { reg: u8, lit: i32 }, + /// 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 + ConstWide { reg: u8, lit: i64 }, + /// 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 + ConstString { reg: u8, lit: DexString }, + /// Move a reference to a class in a register. + ConstClass { reg: u8, lit: IdType }, + /// Acquire the monitor for the object in the register. + MonitorEnter { reg: u8 }, + /// Release the monitor for the object in the register. + MonitorExit { reg: u8 }, + /// Check if the object in the register can be cast to the type. + /// (Raise a `ClassCastException` if not) + CheckCast { reg: u8, lit: IdType }, + /// Check if an object if an instance of a type. + /// (put 1 in the dest register if yes, else 0) + InstanceOf { dest: u8, obj: u8, lit: IdType }, + /// Get the number of item in an array. + /// (put the lenght in the dest register) + ArrayLength { dest: u8, arr: u8 }, + /// Construct a new instance of the indicated type and store a reference to it. + NewInstance { reg: u8, lit: IdType }, + /// Construct a new array of the indicated type and size in size_reg and store a reference to it. + NewArray { reg: u8, size_reg: u8, lit: IdType }, + /// 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. + FilledNewArray { type_: IdType, reg_values: Vec }, + FillArrayData { + arr: u8, + elt_width: u16, + data: Vec, + }, + /// Throws the exception in the register. + Throw { reg: u8 }, + /// Jump to the label. + Goto { label: String }, + /// Jump to a label depending on the value of a register. If the value + /// is not matched, continue the extecution at the next instruction. + Switch { + reg: u8, + #[serde(with = "hashmap_vectorize")] + branches: HashMap, + }, + /// 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 + CmpLFloat { dest: u8, b: u8, c: u8 }, + /// 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 + CmpGFloat { dest: u8, b: u8, c: u8 }, + /// 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 + CmpLDouble { dest: u8, b: u8, c: u8 }, + /// 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 + CmpGDouble { dest: u8, b: u8, c: u8 }, + /// 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 + CmpLong { dest: u8, b: u8, c: u8 }, + /// Jump to the label if a == b + IfEq { a: u8, b: u8, label: String }, + /// Jump to the label if a != b + IfNe { a: u8, b: u8, label: String }, + /// Jump to the label if a < b + IfLt { a: u8, b: u8, label: String }, + /// Jump to the label if a >= b + IfGe { a: u8, b: u8, label: String }, + /// Jump to the label if a > b + IfGt { a: u8, b: u8, label: String }, + /// Jump to the label if a <= b + IfLe { a: u8, b: u8, label: String }, + /// Jump to the label if a == 0 + IfEqZ { a: u8, label: String }, + /// Jump to the label if a != 0 + IfNeZ { a: u8, label: String }, + /// Jump to the label if a < 0 + IfLtZ { a: u8, label: String }, + /// Jump to the label if a >= 0 + IfGeZ { a: u8, label: String }, + /// Jump to the label if a > 0 + IfGtZ { a: u8, label: String }, + /// Jump to the label if a <= 0 + IfLeZ { a: u8, label: String }, + /// Put the value at `arr[idx]` in register dest (all values are in registers) + AGet { dest: u8, arr: u8, idx: u8 }, + /// Put the value at `arr[idx]` in register pair dest (all values are in registers) + AGetWide { dest: u8, arr: u8, idx: u8 }, + /// Put the reference at `arr[idx]` in register (all values are in registers) + AGetObject { dest: u8, arr: u8, idx: u8 }, + /// Put the boolean at `arr[idx]` in register dest (all values are in registers) + AGetBoolean { dest: u8, arr: u8, idx: u8 }, + /// Put the byte at `arr[idx]` in register dest (all values are in registers) + AGetByte { dest: u8, arr: u8, idx: u8 }, + /// Put the char at `arr[idx]` in register dest (all values are in registers) + AGetChar { dest: u8, arr: u8, idx: u8 }, + /// Put the short at `arr[idx]` in register dest (all values are in registers) + AGetShort { dest: u8, arr: u8, idx: u8 }, + /// Put the value of register 'from' in `arr[idx]` (all values are in registers) + APut { from: u8, arr: u8, idx: u8 }, + /// Put the value of the register pair 'from' in `arr[idx]` (all values are in registers) + APutWide { from: u8, arr: u8, idx: u8 }, + /// Put the object reference in 'from' in `arr[idx]` (all values are in registers) + APutObject { from: u8, arr: u8, idx: u8 }, + /// Put the boolean in 'from' in `arr[idx]` (all values are in registers) + APutBoolean { from: u8, arr: u8, idx: u8 }, + /// Put the byte in 'from' in `arr[idx]` (all values are in registers) + APutByte { from: u8, arr: u8, idx: u8 }, + /// Put the char in 'from' in `arr[idx]` (all values are in registers) + APutChar { from: u8, arr: u8, idx: u8 }, + /// Put the short in 'from' in `arr[idx]` (all values are in registers) + APutShort { from: u8, arr: u8, idx: u8 }, + /// 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. + IGet { to: u8, obj: u8, field: IdField }, + /// 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. + IGetWide { to: u8, obj: u8, field: IdField }, + /// 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. + IGetObject { to: u8, obj: u8, field: IdField }, + /// 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. + IGetBoolean { to: u8, obj: u8, field: IdField }, + /// 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. + IGetByte { to: u8, obj: u8, field: IdField }, + /// 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. + IGetChar { to: u8, obj: u8, field: IdField }, + /// 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. + IGetShort { to: u8, obj: u8, field: IdField }, + /// 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. + IPut { from: u8, obj: u8, field: IdField }, + /// 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. + IPutWide { from: u8, obj: u8, field: IdField }, + /// 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. + IPutObject { from: u8, obj: u8, field: IdField }, + /// 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. + IPutBoolean { from: u8, obj: u8, field: IdField }, + /// 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. + IPutByte { from: u8, obj: u8, field: IdField }, + /// 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. + IPutChar { from: u8, obj: u8, field: IdField }, + /// 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. + IPutShort { from: u8, obj: u8, field: IdField }, + /// Put the value in 'to' in the static field 'field' ('to' is a register) + SGet { to: u8, field: IdField }, + /// Put the value in the register pair 'to' in the static field 'field' ('to' is a register) + SGetWide { to: u8, field: IdField }, + /// Put the object reference 'to' in the static field 'field' ('to' is a register) + SGetObject { to: u8, field: IdField }, + /// Put the boolean in 'to' in the static field 'field' ('to' is a register) + SGetBoolean { to: u8, field: IdField }, + /// Put the byte in 'to' in the static field 'field' ('to' is a register) + SGetByte { to: u8, field: IdField }, + /// Put the char in 'to' in the static field 'field' ('to' is a register) + SGetChar { to: u8, field: IdField }, + /// Put the short in 'to' in the static field 'field' ('to' is a register) + SGetShort { to: u8, field: IdField }, + /// Put the value in the static field 'field' in 'from' ('from' is a register) + SPut { from: u8, field: IdField }, + /// Put the value in the static field 'field' in the register pair 'from' + /// ('from' is a register) + SPutWide { from: u8, field: IdField }, + /// Put the object reference in the static field 'field' in 'from' ('from' is a register) + SPutObject { from: u8, field: IdField }, + /// Put the boolean in the static field 'field' in 'from' ('from' is a register) + SPutBoolean { from: u8, field: IdField }, + /// Put the byte in the static field 'field' in 'from' ('from' is a register) + SPutByte { from: u8, field: IdField }, + /// Put the char in the static field 'field' in 'from' ('from' is a register) + SPutChar { from: u8, field: IdField }, + /// Put the short in the static field 'field' in 'from' ('from' is a register) + SPutShort { from: u8, field: IdField }, + /// Call a normal virtual method. + InvokeVirtual { method: IdMethod, args: Vec }, + /// Call the closest superclass's virtual method of a non interface class. + InvokeSuper { method: IdMethod, args: Vec }, + /// Call a direct method (non static non overridable, like private). + InvokeDirect { method: IdMethod, args: Vec }, + /// Call a static method. + InvokeStatic { method: IdMethod, args: Vec }, + /// Call a interface method (method from an interface on an object whose class is unknown) + InvokeInterface { method: IdMethod, args: Vec }, + /// Put -val in dest. + /// `dest` and `val` are registered indexed on 4 bits. + NegInt { dest: u8, val: u8 }, + /// Put ~val in dest + /// `dest` and `val` are registered indexed on 4 bits. + NotInt { dest: u8, val: u8 }, + /// Put -val in dest. dest and val are pair registers. + /// `dest` and `val` are registered indexed on 4 bits. + NegLong { dest: u8, val: u8 }, + /// Put ~val in dest. dest and val are pair registers. + /// `dest` and `val` are registered indexed on 4 bits. + NotLong { dest: u8, val: u8 }, + /// Put -val in dest. + /// `dest` and `val` are registered indexed on 4 bits. + NegFloat { dest: u8, val: u8 }, + /// Put -val in dest. + /// `dest` and `val` are registered indexed on 4 bits. + NegDouble { dest: u8, val: u8 }, + /// Convert copy val to dest an convert to long. + /// TODO: dest is probably a pair register, but is val to? + /// `dest` and `val` are registered indexed on 4 bits. + IntToLong { dest: u8, val: u8 }, + /// Copy val to dest and convert the integer value to a float. + /// `dest` and `val` are registered indexed on 4 bits. + IntToFloat { dest: u8, val: u8 }, + /// Copy val to dest and convert the integer value to a double + /// TODO: dest is probably a pair register, but is val to? + /// `dest` and `val` are registered indexed on 4 bits. + IntToDouble { dest: u8, val: u8 }, + /// Copy val to dest and convert the long value to an integer. + /// TODO: val is probably a pair register, but is dest to? + /// `dest` and `val` are registered indexed on 4 bits. + LongToInt { dest: u8, val: u8 }, + /// Copy val to dest and convert the long value to a float. + /// TODO: val is probably a pair register, but is dest to? + /// `dest` and `val` are registered indexed on 4 bits. + LongToFloat { dest: u8, val: u8 }, + /// Copy val to dest and convert the long value to a double. + /// dest and val are pair registers. + /// `dest` and `val` are registered indexed on 4 bits. + LongToDouble { dest: u8, val: u8 }, + /// Copy val to dest and convert the float value to an integer. + /// `dest` and `val` are registered indexed on 4 bits. + FloatToInt { dest: u8, val: u8 }, + /// Copy val to dest and convert the float value to a long. + /// TODO: dest is probably a pair register, but is val too? + /// `dest` and `val` are registered indexed on 4 bits. + FloatToLong { dest: u8, val: u8 }, + /// Copy val to dest and convert the float value to a double. + /// TODO: dest is probably a pair register, but is val too? + /// `dest` and `val` are registered indexed on 4 bits. + FloatToDouble { dest: u8, val: u8 }, + /// Copy val to dest and convert the double value to an integer. + /// TODO: val is probably a pair register, but is dest too? + /// `dest` and `val` are registered indexed on 4 bits. + DoubleToInt { dest: u8, val: u8 }, + /// Copy val to dest and convert the double value to a long. + /// val and dest are pair registers. + /// `dest` and `val` are registered indexed on 4 bits. + DoubleToLong { dest: u8, val: u8 }, + /// Copy val to dest and convert the double value to a float. + /// TODO: val is probably a pair register, but is dest too? + /// `dest` and `val` are registered indexed on 4 bits. + DoubleToFloat { dest: u8, val: u8 }, + /// Copy val to dest and convert the integer value to a byte. + /// `dest` and `val` are registered indexed on 4 bits. + IntToByte { dest: u8, val: u8 }, + /// Copy val to dest and convert the integer value to a char. + /// `dest` and `val` are registered indexed on 4 bits. + IntToChar { dest: u8, val: u8 }, + /// Copy val to dest and convert the integer value to a short. + /// `dest` and `val` are registered indexed on 4 bits. + IntToShort { dest: u8, val: u8 }, + /// Put a + b in dest. + AddInt { dest: u8, b: u8, c: u8 }, + /// Put a - b in dest. + SubInt { dest: u8, b: u8, c: u8 }, + /// Put a * b in dest. + MulInt { dest: u8, b: u8, c: u8 }, + /// Put a / b in dest. + DivInt { dest: u8, b: u8, c: u8 }, + /// Put a % b in dest. + RemInt { dest: u8, b: u8, c: u8 }, + /// Put a & b in dest. + AndInt { dest: u8, b: u8, c: u8 }, + /// Put a | b in dest. + OrInt { dest: u8, b: u8, c: u8 }, + /// Put a ^ b in dest. + XorInt { dest: u8, b: u8, c: u8 }, + /// Put a << b in dest. + ShlInt { dest: u8, b: u8, c: u8 }, + /// Put a >> b (signed) in dest. + ShrInt { dest: u8, b: u8, c: u8 }, + /// Put a >> b in dest. + UshrInt { dest: u8, b: u8, c: u8 }, + /// Put a + b in dest. + /// dest, b and c are register pairs + AddLong { dest: u8, b: u8, c: u8 }, + /// Put a - b in dest. + /// dest, b and c are register pairs + SubLong { dest: u8, b: u8, c: u8 }, + /// Put a * b in dest. + /// dest, b and c are register pairs + MulLong { dest: u8, b: u8, c: u8 }, + /// Put a / b in dest. + /// dest, b and c are register pairs + DivLong { dest: u8, b: u8, c: u8 }, + /// Put a % b in dest. + /// dest, b and c are register pairs + RemLong { dest: u8, b: u8, c: u8 }, + /// Put a & b in dest. + /// dest, b and c are register pairs + AndLong { dest: u8, b: u8, c: u8 }, + /// Put a | b in dest. + /// dest, b and c are register pairs + OrLong { dest: u8, b: u8, c: u8 }, + /// Put a ^ b in dest. + /// dest, b and c are register pairs + XorLong { dest: u8, b: u8, c: u8 }, + /// Put a << b in dest. + /// dest, and b are register pairs, and c is a single register + ShlLong { dest: u8, b: u8, c: u8 }, + /// Put a >> b (signed) in dest. + /// dest, and b are register pairs, and c is a single register + ShrLong { dest: u8, b: u8, c: u8 }, + /// Put a >> b in dest. + /// dest, and b are register pairs, and c is a single register + UshrLong { dest: u8, b: u8, c: u8 }, + /// Put a + b in dest. + AddFloat { dest: u8, b: u8, c: u8 }, + /// Put a - b in dest. + SubFloat { dest: u8, b: u8, c: u8 }, + /// Put a * b in dest. + MulFloat { dest: u8, b: u8, c: u8 }, + /// Put a / b in dest. + DivFloat { dest: u8, b: u8, c: u8 }, + /// Put a % b in dest. + RemFloat { dest: u8, b: u8, c: u8 }, + /// Put a + b in dest. + /// dest, b and c are register pairs + AddDouble { dest: u8, b: u8, c: u8 }, + /// Put a - b in dest. + /// dest, b and c are register pairs + SubDouble { dest: u8, b: u8, c: u8 }, + /// Put a * b in dest. + /// dest, b and c are register pairs + MulDouble { dest: u8, b: u8, c: u8 }, + /// Put a / b in dest. + /// dest, b and c are register pairs + DivDouble { dest: u8, b: u8, c: u8 }, + /// Put a % b in dest. + /// dest, b and c are register pairs + RemDouble { dest: u8, b: u8, c: u8 }, + /// Put dest + b in dest. + /// `dest` and `b` are registers indexed on 4 bits + AddInt2Addr { dest: u8, b: u8 }, + /// Put dest - b in dest. + /// `dest` and `b` are registers indexed on 4 bits + SubInt2Addr { dest: u8, b: u8 }, + /// Put dest * b in dest. + /// `dest` and `b` are registers indexed on 4 bits + MulInt2Addr { dest: u8, b: u8 }, + /// Put dest / b in dest. + /// `dest` and `b` are registers indexed on 4 bits + DivInt2Addr { dest: u8, b: u8 }, + /// Put dest % b in dest. + /// `dest` and `b` are registers indexed on 4 bits + RemInt2Addr { dest: u8, b: u8 }, + /// Put dest & b in dest. + /// `dest` and `b` are registers indexed on 4 bits + AndInt2Addr { dest: u8, b: u8 }, + /// Put dest | b in dest. + /// `dest` and `b` are registers indexed on 4 bits + OrInt2Addr { dest: u8, b: u8 }, + /// Put dest ^ b in dest. + /// `dest` and `b` are registers indexed on 4 bits + XorInt2Addr { dest: u8, b: u8 }, + /// Put dest << b in dest. + /// `dest` and `b` are registers indexed on 4 bits + ShlInt2Addr { dest: u8, b: u8 }, + /// Put dest >> b (signed) in dest. + /// `dest` and `b` are registers indexed on 4 bits + ShrInt2Addr { dest: u8, b: u8 }, + /// Put dest >> b in dest. + /// `dest` and `b` are registers indexed on 4 bits + UshrInt2Addr { dest: u8, b: u8 }, + /// Put dest + b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + AddLong2Addr { dest: u8, b: u8 }, + /// Put dest - b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + SubLong2Addr { dest: u8, b: u8 }, + /// Put dest * b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + MulLong2Addr { dest: u8, b: u8 }, + /// Put dest / b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + DivLong2Addr { dest: u8, b: u8 }, + /// Put dest % b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + RemLong2Addr { dest: u8, b: u8 }, + /// Put dest & b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + AndLong2Addr { dest: u8, b: u8 }, + /// Put dest | b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + OrLong2Addr { dest: u8, b: u8 }, + /// Put dest ^ b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + XorLong2Addr { dest: u8, b: u8 }, + /// Put dest << b in dest. + /// dest is a register pair, and b is a single register + /// `dest` and `b` are registers indexed on 4 bits + ShlLong2Addr { dest: u8, b: u8 }, + /// Put dest >> b (signed) in dest. + /// dest is a register pair, and b is a single register + /// `dest` and `b` are registers indexed on 4 bits + ShrLong2Addr { dest: u8, b: u8 }, + /// Put dest >> b in dest. + /// dest is a register pair, and b is a single register + /// `dest` and `b` are registers indexed on 4 bits + UshrLong2Addr { dest: u8, b: u8 }, + /// Put dest + b in dest. + /// `dest` and `b` are registers indexed on 4 bits + AddFloat2Addr { dest: u8, b: u8 }, + /// Put dest - b in dest. + /// `dest` and `b` are registers indexed on 4 bits + SubFloat2Addr { dest: u8, b: u8 }, + /// Put dest * b in dest. + /// `dest` and `b` are registers indexed on 4 bits + MulFloat2Addr { dest: u8, b: u8 }, + /// Put dest / b in dest. + /// `dest` and `b` are registers indexed on 4 bits + DivFloat2Addr { dest: u8, b: u8 }, + /// Put dest % b in dest. + /// `dest` and `b` are registers indexed on 4 bits + RemFloat2Addr { dest: u8, b: u8 }, + /// Put dest + b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + AddDouble2Addr { dest: u8, b: u8 }, + /// Put dest - b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + SubDouble2Addr { dest: u8, b: u8 }, + /// Put dest * b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + MulDouble2Addr { dest: u8, b: u8 }, + /// Put dest / b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + DivDouble2Addr { dest: u8, b: u8 }, + /// Put dest % b in dest. + /// dest and b are register pairs + /// `dest` and `b` are registers indexed on 4 bits + RemDouble2Addr { dest: u8, b: u8 }, + /// Put b + lit in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + AddIntLit { dest: u8, b: u8, lit: i16 }, + /// Put lit - b in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + RsubIntLit { dest: u8, b: u8, lit: i16 }, + /// Put b * lit in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + MulIntLit { dest: u8, b: u8, lit: i16 }, + /// Put b / lit in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + DivIntLit { dest: u8, b: u8, lit: i16 }, + /// Put b % lit in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + RemIntLit { dest: u8, b: u8, lit: i16 }, + /// Put b & lit in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + AndIntLit { dest: u8, b: u8, lit: i16 }, + /// Put b | lit in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + OrIntLit { dest: u8, b: u8, lit: i16 }, + /// Put b ^ lit in dest. + /// Either `dest` and `b` are registers indexed on 4 bits and lit is encoded in 16 bits + /// or `dest` and `b` are registers indexed on 8 bits and lit is encoded in 8 bits + XorIntLit { dest: u8, b: u8, lit: i16 }, + /// Put b << lit in dest. + ShlIntLit { dest: u8, b: u8, lit: i8 }, + /// Put b >> lit (signed) in dest. + ShrIntLit { dest: u8, b: u8, lit: i8 }, + /// Put b >> lit in dest. + UshrIntLit { dest: u8, b: u8, lit: i8 }, + /// Call a polymorphic method. + InvokePolymorphic { + method: IdMethod, + proto: IdMethodType, + args: Vec, + }, + /// Invoke a method from a call site. + InvokeCustom { call_site: CallSite, args: Vec }, + /// Put contents reference to the method handle in the register. + ConstMethodHandle { handle: MethodHandle, to: u8 }, + /// Put contents reference to the prototype in the register. + ConstMethodType { proto: IdMethodType, to: u8 }, + /// Try block. It does not match an dalvik instruction but is derived from the code item struct. + Try { + end_label: String, + /// The list of exceptions and their associated handler label. + /// + /// + /// The handler are sorted: if severat Exception Type match an exceptions, the + /// the handler used is the first in the list. + handlers: Vec<(IdType, String)>, + default_handler: Option, + }, + /// Label marker. It does not match an dalvik instruction, but it's use as a marker for a + /// jump destination. + Label { name: String }, } impl Visitable for Instruction { - fn default_visit(&self, _visitor: &mut V) -> Result<()> { + fn default_visit(&self, v: &mut V) -> Result<()> { + // TODO wildcard? match self { Self::Nop {} => Ok(()), - Self::Move(_ins) => todo!(), - Self::MoveWide(_ins) => todo!(), - Self::MoveObject(_ins) => todo!(), - Self::MoveResult(_ins) => todo!(), - Self::MoveResultWide(_ins) => todo!(), - Self::MoveException(_ins) => todo!(), - Self::MoveResultObject(_ins) => todo!(), - Self::ReturnVoid(_ins) => todo!(), - Self::Return(_ins) => todo!(), - Self::ReturnWide(_ins) => todo!(), - Self::ReturnObject(_ins) => todo!(), - Self::Const(_ins) => todo!(), - Self::ConstWide(_ins) => todo!(), - Self::ConstString(_ins) => todo!(), - Self::ConstClass(_ins) => todo!(), - Self::MonitorEnter(_ins) => todo!(), - Self::MonitorExit(_ins) => todo!(), - Self::CheckCast(_ins) => todo!(), - Self::InstanceOf(_ins) => todo!(), - Self::ArrayLength(_ins) => todo!(), - Self::NewInstance(_ins) => todo!(), - Self::NewArray(_ins) => todo!(), - Self::FilledNewArray(_ins) => todo!(), - Self::FillArrayData(_ins) => todo!(), - Self::Throw(_ins) => todo!(), - Self::Goto(_ins) => todo!(), - Self::Switch(_ins) => todo!(), - Self::CmpLFloat(_ins) => todo!(), - Self::CmpGFloat(_ins) => todo!(), - Self::CmpLDouble(_ins) => todo!(), - Self::CmpGDouble(_ins) => todo!(), - Self::CmpLong(_ins) => todo!(), - Self::IfEq(_ins) => todo!(), - Self::IfNe(_ins) => todo!(), - Self::IfLt(_ins) => todo!(), - Self::IfGe(_ins) => todo!(), - Self::IfGt(_ins) => todo!(), - Self::IfLe(_ins) => todo!(), - Self::IfEqZ(_ins) => todo!(), - Self::IfNeZ(_ins) => todo!(), - Self::IfLtZ(_ins) => todo!(), - Self::IfGeZ(_ins) => todo!(), - Self::IfGtZ(_ins) => todo!(), - Self::IfLeZ(_ins) => todo!(), - Self::AGet(_ins) => todo!(), - Self::AGetWide(_ins) => todo!(), - Self::AGetObject(_ins) => todo!(), - Self::AGetBoolean(_ins) => todo!(), - Self::AGetByte(_ins) => todo!(), - Self::AGetChar(_ins) => todo!(), - Self::AGetShort(_ins) => todo!(), - Self::APut(_ins) => todo!(), - Self::APutWide(_ins) => todo!(), - Self::APutObject(_ins) => todo!(), - Self::APutBoolean(_ins) => todo!(), - Self::APutByte(_ins) => todo!(), - Self::APutChar(_ins) => todo!(), - Self::APutShort(_ins) => todo!(), - Self::IGet(_ins) => todo!(), - Self::IGetWide(_ins) => todo!(), - Self::IGetObject(_ins) => todo!(), - Self::IGetBoolean(_ins) => todo!(), - Self::IGetByte(_ins) => todo!(), - Self::IGetChar(_ins) => todo!(), - Self::IGetShort(_ins) => todo!(), - Self::IPut(_ins) => todo!(), - Self::IPutWide(_ins) => todo!(), - Self::IPutObject(_ins) => todo!(), - Self::IPutBoolean(_ins) => todo!(), - Self::IPutByte(_ins) => todo!(), - Self::IPutChar(_ins) => todo!(), - Self::IPutShort(_ins) => todo!(), - Self::SGet(_ins) => todo!(), - Self::SGetWide(_ins) => todo!(), - Self::SGetObject(_ins) => todo!(), - Self::SGetBoolean(_ins) => todo!(), - Self::SGetByte(_ins) => todo!(), - Self::SGetChar(_ins) => todo!(), - Self::SGetShort(_ins) => todo!(), - Self::SPut(_ins) => todo!(), - Self::SPutWide(_ins) => todo!(), - Self::SPutObject(_ins) => todo!(), - Self::SPutBoolean(_ins) => todo!(), - Self::SPutByte(_ins) => todo!(), - Self::SPutChar(_ins) => todo!(), - Self::SPutShort(_ins) => todo!(), - Self::InvokeVirtual(_ins) => todo!(), - Self::InvokeSuper(_ins) => todo!(), - Self::InvokeDirect(_ins) => todo!(), - Self::InvokeStatic(_ins) => todo!(), - Self::InvokeInterface(_ins) => todo!(), - Self::NegInt(_ins) => todo!(), - Self::NotInt(_ins) => todo!(), - Self::NegLong(_ins) => todo!(), - Self::NotLong(_ins) => todo!(), - Self::NegFloat(_ins) => todo!(), - Self::NegDouble(_ins) => todo!(), - Self::IntToLong(_ins) => todo!(), - Self::IntToFloat(_ins) => todo!(), - Self::IntToDouble(_ins) => todo!(), - Self::LongToInt(_ins) => todo!(), - Self::LongToFloat(_ins) => todo!(), - Self::LongToDouble(_ins) => todo!(), - Self::FloatToInt(_ins) => todo!(), - Self::FloatToLong(_ins) => todo!(), - Self::FloatToDouble(_ins) => todo!(), - Self::DoubleToInt(_ins) => todo!(), - Self::DoubleToLong(_ins) => todo!(), - Self::DoubleToFloat(_ins) => todo!(), - Self::IntToByte(_ins) => todo!(), - Self::IntToChar(_ins) => todo!(), - Self::IntToShort(_ins) => todo!(), - Self::AddInt(_ins) => todo!(), - Self::SubInt(_ins) => todo!(), - Self::MulInt(_ins) => todo!(), - Self::DivInt(_ins) => todo!(), - Self::RemInt(_ins) => todo!(), - Self::AndInt(_ins) => todo!(), - Self::OrInt(_ins) => todo!(), - Self::XorInt(_ins) => todo!(), - Self::ShlInt(_ins) => todo!(), - Self::ShrInt(_ins) => todo!(), - Self::UshrInt(_ins) => todo!(), - Self::AddLong(_ins) => todo!(), - Self::SubLong(_ins) => todo!(), - Self::MulLong(_ins) => todo!(), - Self::DivLong(_ins) => todo!(), - Self::RemLong(_ins) => todo!(), - Self::AndLong(_ins) => todo!(), - Self::OrLong(_ins) => todo!(), - Self::XorLong(_ins) => todo!(), - Self::ShlLong(_ins) => todo!(), - Self::ShrLong(_ins) => todo!(), - Self::UshrLong(_ins) => todo!(), - Self::AddFloat(_ins) => todo!(), - Self::SubFloat(_ins) => todo!(), - Self::MulFloat(_ins) => todo!(), - Self::DivFloat(_ins) => todo!(), - Self::RemFloat(_ins) => todo!(), - Self::AddDouble(_ins) => todo!(), - Self::SubDouble(_ins) => todo!(), - Self::MulDouble(_ins) => todo!(), - Self::DivDouble(_ins) => todo!(), - Self::RemDouble(_ins) => todo!(), - Self::AddInt2Addr(_ins) => todo!(), - Self::SubInt2Addr(_ins) => todo!(), - Self::MulInt2Addr(_ins) => todo!(), - Self::DivInt2Addr(_ins) => todo!(), - Self::RemInt2Addr(_ins) => todo!(), - Self::AndInt2Addr(_ins) => todo!(), - Self::OrInt2Addr(_ins) => todo!(), - Self::XorInt2Addr(_ins) => todo!(), - Self::ShlInt2Addr(_ins) => todo!(), - Self::ShrInt2Addr(_ins) => todo!(), - Self::UshrInt2Addr(_ins) => todo!(), - Self::AddLong2Addr(_ins) => todo!(), - Self::SubLong2Addr(_ins) => todo!(), - Self::MulLong2Addr(_ins) => todo!(), - Self::DivLong2Addr(_ins) => todo!(), - Self::RemLong2Addr(_ins) => todo!(), - Self::AndLong2Addr(_ins) => todo!(), - Self::OrLong2Addr(_ins) => todo!(), - Self::XorLong2Addr(_ins) => todo!(), - Self::ShlLong2Addr(_ins) => todo!(), - Self::ShrLong2Addr(_ins) => todo!(), - Self::UshrLong2Addr(_ins) => todo!(), - Self::AddFloat2Addr(_ins) => todo!(), - Self::SubFloat2Addr(_ins) => todo!(), - Self::MulFloat2Addr(_ins) => todo!(), - Self::DivFloat2Addr(_ins) => todo!(), - Self::RemFloat2Addr(_ins) => todo!(), - Self::AddDouble2Addr(_ins) => todo!(), - Self::SubDouble2Addr(_ins) => todo!(), - Self::MulDouble2Addr(_ins) => todo!(), - Self::DivDouble2Addr(_ins) => todo!(), - Self::RemDouble2Addr(_ins) => todo!(), - Self::AddIntLit(_ins) => todo!(), - Self::RsubIntLit(_ins) => todo!(), - Self::MulIntLit(_ins) => todo!(), - Self::DivIntLit(_ins) => todo!(), - Self::RemIntLit(_ins) => todo!(), - Self::AndIntLit(_ins) => todo!(), - Self::OrIntLit(_ins) => todo!(), - Self::XorIntLit(_ins) => todo!(), - Self::ShlIntLit(_ins) => todo!(), - Self::ShrIntLit(_ins) => todo!(), - Self::UshrIntLit(_ins) => todo!(), - Self::InvokePolymorphic(_ins) => todo!(), - Self::InvokeCustom(_ins) => todo!(), - Self::ConstMethodHandle(_ins) => todo!(), - Self::ConstMethodType(_ins) => todo!(), - Self::Try(_ins) => todo!(), - Self::Label(_ins) => todo!(), + Self::Move { from: _, to: _ } => Ok(()), + Self::MoveWide { from: _, to: _ } => Ok(()), + Self::MoveObject { from: _, to: _ } => Ok(()), + Self::MoveResult { to: _ } => Ok(()), + Self::MoveResultWide { to: _ } => Ok(()), + Self::MoveException { to: _ } => Ok(()), + Self::MoveResultObject { to: _ } => Ok(()), + Self::ReturnVoid {} => Ok(()), + Self::Return { reg: _ } => Ok(()), + Self::ReturnWide { reg: _ } => Ok(()), + Self::ReturnObject { reg: _ } => Ok(()), + Self::Const { reg: _, lit: _ } => Ok(()), + Self::ConstWide { reg: _, lit: _ } => Ok(()), + Self::ConstString { reg: _, lit } => v.visit_string(lit), + Self::ConstClass { reg: _, lit } => v.visit_type(lit), + Self::MonitorEnter { reg: _ } => Ok(()), + Self::MonitorExit { reg: _ } => Ok(()), + Self::CheckCast { reg: _, lit } => v.visit_type(lit), + Self::InstanceOf { + dest: _, + obj: _, + lit, + } => v.visit_type(lit), + Self::ArrayLength { dest: _, arr: _ } => Ok(()), + Self::NewInstance { reg: _, lit } => v.visit_type(lit), + Self::NewArray { + reg: _, + size_reg: _, + lit, + } => v.visit_type(lit), + Self::FilledNewArray { + type_, + reg_values: _, + } => v.visit_type(type_), + Self::FillArrayData { + arr: _, + elt_width: _, + data: _, + } => Ok(()), + Self::Throw { reg: _ } => Ok(()), + Self::Goto { label: _ } => Ok(()), + Self::Switch { + reg: _, + branches: _, + } => Ok(()), + Self::CmpLFloat { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::CmpGFloat { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::CmpLDouble { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::CmpGDouble { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::CmpLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::IfEq { + a: _, + b: _, + label: _, + } => Ok(()), + Self::IfNe { + a: _, + b: _, + label: _, + } => Ok(()), + Self::IfLt { + a: _, + b: _, + label: _, + } => Ok(()), + Self::IfGe { + a: _, + b: _, + label: _, + } => Ok(()), + Self::IfGt { + a: _, + b: _, + label: _, + } => Ok(()), + Self::IfLe { + a: _, + b: _, + label: _, + } => Ok(()), + Self::IfEqZ { a: _, label: _ } => Ok(()), + Self::IfNeZ { a: _, label: _ } => Ok(()), + Self::IfLtZ { a: _, label: _ } => Ok(()), + Self::IfGeZ { a: _, label: _ } => Ok(()), + Self::IfGtZ { a: _, label: _ } => Ok(()), + Self::IfLeZ { a: _, label: _ } => Ok(()), + Self::AGet { + dest: _, + arr: _, + idx: _, + } => Ok(()), + Self::AGetWide { + dest: _, + arr: _, + idx: _, + } => Ok(()), + Self::AGetObject { + dest: _, + arr: _, + idx: _, + } => Ok(()), + Self::AGetBoolean { + dest: _, + arr: _, + idx: _, + } => Ok(()), + Self::AGetByte { + dest: _, + arr: _, + idx: _, + } => Ok(()), + Self::AGetChar { + dest: _, + arr: _, + idx: _, + } => Ok(()), + Self::AGetShort { + dest: _, + arr: _, + idx: _, + } => Ok(()), + Self::APut { + from: _, + arr: _, + idx: _, + } => Ok(()), + Self::APutWide { + from: _, + arr: _, + idx: _, + } => Ok(()), + Self::APutObject { + from: _, + arr: _, + idx: _, + } => Ok(()), + Self::APutBoolean { + from: _, + arr: _, + idx: _, + } => Ok(()), + Self::APutByte { + from: _, + arr: _, + idx: _, + } => Ok(()), + Self::APutChar { + from: _, + arr: _, + idx: _, + } => Ok(()), + Self::APutShort { + from: _, + arr: _, + idx: _, + } => Ok(()), + Self::IGet { + to: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IGetWide { + to: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IGetObject { + to: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IGetBoolean { + to: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IGetByte { + to: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IGetChar { + to: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IGetShort { + to: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IPut { + from: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IPutWide { + from: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IPutObject { + from: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IPutBoolean { + from: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IPutByte { + from: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IPutChar { + from: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::IPutShort { + from: _, + obj: _, + field, + } => v.visit_field_id(field), + Self::SGet { + to: _, + field, + } => v.visit_field_id(field), + Self::SGetWide { + to: _, + field, + } => v.visit_field_id(field), + Self::SGetObject { + to: _, + field, + } => v.visit_field_id(field), + Self::SGetBoolean { + to: _, + field, + } => v.visit_field_id(field),, + Self::SGetByte { + to: _, + field, + } => v.visit_field_id(field),, + Self::SGetChar { + to: _, + field, + } => v.visit_field_id(field),, + Self::SGetShort { + to: _, + field, + } => v.visit_field_id(field),, + Self::SPut { + from: _, + field, + } => v.visit_field_id(field),, + Self::SPutWide { + from: _, + field, + } => v.visit_field_id(field),, + Self::SPutObject { + from: _, + field, + } => v.visit_field_id(field),, + Self::SPutBoolean { + from: _, + field, + } => v.visit_field_id(field),, + Self::SPutByte { + from: _, + field, + } => v.visit_field_id(field),, + Self::SPutChar { + from: _, + field, + } => v.visit_field_id(field),, + Self::SPutShort { + from: _, + field, + } => v.visit_field_id(field),, + Self::InvokeVirtual { method, args: _ } => v.visit_method_id(method), + Self::InvokeSuper { method, args: _ } => v.visit_method_id(method), + Self::InvokeDirect { method, args: _ } => v.visit_method_id(method), + Self::InvokeStatic { method, args: _ } => v.visit_method_id(method), + Self::InvokeInterface { method, args: _ } => v.visit_method_id(method), + Self::NegInt { dest: _, val: _ } => Ok(()), + Self::NotInt { dest: _, val: _ } => Ok(()), + Self::NegLong { dest: _, val: _ } => Ok(()), + Self::NotLong { dest: _, val: _ } => Ok(()), + Self::NegFloat { dest: _, val: _ } => Ok(()), + Self::NegDouble { dest: _, val: _ } => Ok(()), + Self::IntToLong { dest: _, val: _ } => Ok(()), + Self::IntToFloat { dest: _, val: _ } => Ok(()), + Self::IntToDouble { dest: _, val: _ } => Ok(()), + Self::LongToInt { dest: _, val: _ } => Ok(()), + Self::LongToFloat { dest: _, val: _ } => Ok(()), + Self::LongToDouble { dest: _, val: _ } => Ok(()), + Self::FloatToInt { dest: _, val: _ } => Ok(()), + Self::FloatToLong { dest: _, val: _ } => Ok(()), + Self::FloatToDouble { dest: _, val: _ } => Ok(()), + Self::DoubleToInt { dest: _, val: _ } => Ok(()), + Self::DoubleToLong { dest: _, val: _ } => Ok(()), + Self::DoubleToFloat { dest: _, val: _ } => Ok(()), + Self::IntToByte { dest: _, val: _ } => Ok(()), + Self::IntToChar { dest: _, val: _ } => Ok(()), + Self::IntToShort { dest: _, val: _ } => Ok(()), + Self::AddInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::SubInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::MulInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::DivInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::RemInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::AndInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::OrInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::XorInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::ShlInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::ShrInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::UshrInt { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::AddLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::SubLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::MulLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::DivLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::RemLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::AndLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::OrLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::XorLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::ShlLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::ShrLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::UshrLong { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::AddFloat { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::SubFloat { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::MulFloat { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::DivFloat { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::RemFloat { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::AddDouble { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::SubDouble { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::MulDouble { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::DivDouble { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::RemDouble { + dest: _, + b: _, + c: _, + } => Ok(()), + Self::AddInt2Addr { dest: _, b: _ } => Ok(()), + Self::SubInt2Addr { dest: _, b: _ } => Ok(()), + Self::MulInt2Addr { dest: _, b: _ } => Ok(()), + Self::DivInt2Addr { dest: _, b: _ } => Ok(()), + Self::RemInt2Addr { dest: _, b: _ } => Ok(()), + Self::AndInt2Addr { dest: _, b: _ } => Ok(()), + Self::OrInt2Addr { dest: _, b: _ } => Ok(()), + Self::XorInt2Addr { dest: _, b: _ } => Ok(()), + Self::ShlInt2Addr { dest: _, b: _ } => Ok(()), + Self::ShrInt2Addr { dest: _, b: _ } => Ok(()), + Self::UshrInt2Addr { dest: _, b: _ } => Ok(()), + Self::AddLong2Addr { dest: _, b: _ } => Ok(()), + Self::SubLong2Addr { dest: _, b: _ } => Ok(()), + Self::MulLong2Addr { dest: _, b: _ } => Ok(()), + Self::DivLong2Addr { dest: _, b: _ } => Ok(()), + Self::RemLong2Addr { dest: _, b: _ } => Ok(()), + Self::AndLong2Addr { dest: _, b: _ } => Ok(()), + Self::OrLong2Addr { dest: _, b: _ } => Ok(()), + Self::XorLong2Addr { dest: _, b: _ } => Ok(()), + Self::ShlLong2Addr { dest: _, b: _ } => Ok(()), + Self::ShrLong2Addr { dest: _, b: _ } => Ok(()), + Self::UshrLong2Addr { dest: _, b: _ } => Ok(()), + Self::AddFloat2Addr { dest: _, b: _ } => Ok(()), + Self::SubFloat2Addr { dest: _, b: _ } => Ok(()), + Self::MulFloat2Addr { dest: _, b: _ } => Ok(()), + Self::DivFloat2Addr { dest: _, b: _ } => Ok(()), + Self::RemFloat2Addr { dest: _, b: _ } => Ok(()), + Self::AddDouble2Addr { dest: _, b: _ } => Ok(()), + Self::SubDouble2Addr { dest: _, b: _ } => Ok(()), + Self::MulDouble2Addr { dest: _, b: _ } => Ok(()), + Self::DivDouble2Addr { dest: _, b: _ } => Ok(()), + Self::RemDouble2Addr { dest: _, b: _ } => Ok(()), + Self::AddIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::RsubIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::MulIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::DivIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::RemIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::AndIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::OrIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::XorIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::ShlIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::ShrIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::UshrIntLit { + dest: _, + b: _, + lit: _, + } => Ok(()), + Self::InvokePolymorphic { + method, + proto, + args: _, + } => { + v.visit_method_id(method)?; + v.visit_method_type(proto) + } + Self::InvokeCustom { call_site, args: _ } => v.visit_call_site(call_site), + Self::ConstMethodHandle { handle, to: _ } => v.visit_method_handle(handle), + Self::ConstMethodType { proto, to: _ } => v.visit_method_type(proto), + Self::Try { + end_label: _, + handlers, + default_handler: _, + } => { + for (ty, _) in handlers { + v.visit_type(ty)?; + } + Ok(()) + } + Self::Label { name: _ } => todo!(), } } } diff --git a/androscalpel/src/visitor.rs b/androscalpel/src/visitor.rs index e58110c..27ef6b6 100644 --- a/androscalpel/src/visitor.rs +++ b/androscalpel/src/visitor.rs @@ -1,8 +1,8 @@ //! The visitor trait and common implementations. use crate::{ - ins::Instruction, DexString, IdEnum, IdField, IdMethod, IdMethodType, IdType, MethodHandle, - Result, + ins::Instruction, CallSite, DexString, IdEnum, IdField, IdMethod, IdMethodType, IdType, + MethodHandle, Result, }; use std::collections::HashSet; @@ -31,6 +31,9 @@ pub trait Visitor: Sized { fn visit_method_handle(&mut self, handle: &MethodHandle) -> Result<()> { handle.default_visit(self) } + fn visit_call_site(&mut self, site: &CallSite) -> Result<()> { + site.default_visit(self) + } } pub trait VisitorMut: Sized { @@ -58,6 +61,9 @@ pub trait VisitorMut: Sized { fn visit_method_handle(&mut self, handle: MethodHandle) -> Result { handle.default_visit_mut(self) } + fn visit_call_site(&mut self, site: CallSite) -> Result { + site.default_visit_mut(self) + } } /// Trait for structures that can be visited.