should remive the 12 reg limit
This commit is contained in:
parent
d846afa878
commit
540e0223fc
3 changed files with 504 additions and 28 deletions
8
patcher/Cargo.lock
generated
8
patcher/Cargo.lock
generated
|
|
@ -35,7 +35,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "androscalpel"
|
name = "androscalpel"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=95c6b62#95c6b624ae31254d2f67c2f3d13c0a96217a6ec1"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"adler",
|
||||||
"androscalpel_serializer",
|
"androscalpel_serializer",
|
||||||
|
|
@ -51,7 +51,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "androscalpel_serializer"
|
name = "androscalpel_serializer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=95c6b62#95c6b624ae31254d2f67c2f3d13c0a96217a6ec1"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"androscalpel_serializer_derive",
|
"androscalpel_serializer_derive",
|
||||||
"log",
|
"log",
|
||||||
|
|
@ -60,7 +60,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "androscalpel_serializer_derive"
|
name = "androscalpel_serializer_derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=95c6b62#95c6b624ae31254d2f67c2f3d13c0a96217a6ec1"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -129,7 +129,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "apk_frauder"
|
name = "apk_frauder"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=95c6b62#95c6b624ae31254d2f67c2f3d13c0a96217a6ec1"
|
source = "git+ssh://git@git.mineau.eu/histausse/androscalpel.git?rev=f15ad78#f15ad78d44d78d188580698a2cfd3da1b0f4389d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"androscalpel_serializer",
|
"androscalpel_serializer",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
androscalpel = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "95c6b62", features = ["code-analysis"] }
|
androscalpel = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "f15ad78", features = ["code-analysis"] }
|
||||||
apk_frauder = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "95c6b62"}
|
apk_frauder = { git = "ssh://git@git.mineau.eu/histausse/androscalpel.git", rev = "f15ad78"}
|
||||||
anyhow = "1.0.95"
|
anyhow = "1.0.95"
|
||||||
clap = { version = "4.5.27", features = ["derive"] }
|
clap = { version = "4.5.27", features = ["derive"] }
|
||||||
env_logger = "0.11.6"
|
env_logger = "0.11.6"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use androscalpel::SmaliName;
|
use androscalpel::SmaliName;
|
||||||
use androscalpel::{IdMethod, IdType, Instruction, Method};
|
use androscalpel::{IdMethod, IdType, Instruction, Method, RegType};
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
@ -145,6 +145,7 @@ pub struct ReflectionCnstrNewInstData {
|
||||||
/// before using them.
|
/// before using them.
|
||||||
///
|
///
|
||||||
/// `first_arg` is the first register of plage of `nb_arg_reg` use to invoke method.
|
/// `first_arg` is the first register of plage of `nb_arg_reg` use to invoke method.
|
||||||
|
#[derive(PartialEq, Debug, Default)]
|
||||||
struct RegistersInfo {
|
struct RegistersInfo {
|
||||||
pub array_index: u8,
|
pub array_index: u8,
|
||||||
pub array: u8,
|
pub array: u8,
|
||||||
|
|
@ -156,6 +157,386 @@ struct RegistersInfo {
|
||||||
pub nb_arg_reg: u16,
|
pub nb_arg_reg: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RegistersInfo {
|
||||||
|
pub fn get_nb_added_reg(&self) -> u16 {
|
||||||
|
self.nb_arg_reg + 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the values for `array_index`, `array` and `array_val` when the methode already use more
|
||||||
|
/// than 12 registers. This means already used registers need to be saved in order to be used.
|
||||||
|
/// The first instruction vec return contains the instructions to save the registers, the
|
||||||
|
/// second the instructions to restore the registers to their old values.
|
||||||
|
///
|
||||||
|
/// `used_reg` is a list of register that cannot be used because directly used by the invoke
|
||||||
|
/// instruction or the move-result ibstruction.
|
||||||
|
/// `regs_type` is the type of the registers at this point in the code of the method.
|
||||||
|
pub fn tmp_reserve_reg(
|
||||||
|
&mut self,
|
||||||
|
used_reg: &[u16],
|
||||||
|
regs_type: &[RegType],
|
||||||
|
) -> Result<(Vec<Instruction>, Vec<Instruction>)> {
|
||||||
|
let mut used_reg = used_reg.to_vec();
|
||||||
|
let mut save_reg_insns = vec![];
|
||||||
|
let mut restore_reg_insns = vec![];
|
||||||
|
if let Some(reg_save) = self.array_val_save {
|
||||||
|
let mut found = false;
|
||||||
|
if reg_save <= 0b1110 {
|
||||||
|
// This should not happend, but who knows?
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16))
|
||||||
|
&& !used_reg.contains(&((i + 1) as u16))
|
||||||
|
&& regs_type[i] == RegType::FirstWideScalar
|
||||||
|
&& regs_type[i + 1] == RegType::SecondWideScalar
|
||||||
|
{
|
||||||
|
self.array_val = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
used_reg.push((i + 1) as u16);
|
||||||
|
save_reg_insns.push(Instruction::MoveWide {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::MoveWide {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16))
|
||||||
|
&& !used_reg.contains(&((i + 1) as u16))
|
||||||
|
&& (regs_type[i] == RegType::Object
|
||||||
|
|| regs_type[i] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
|| regs_type[i] == RegType::Undefined)
|
||||||
|
&& (regs_type[i + 1] == RegType::Object
|
||||||
|
|| regs_type[i + 1] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i + 1] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i + 1] == RegType::SecondWideScalar
|
||||||
|
|| regs_type[i + 1] == RegType::Undefined)
|
||||||
|
{
|
||||||
|
self.array_val = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
used_reg.push((i + 1) as u16);
|
||||||
|
if regs_type[i] == RegType::Object {
|
||||||
|
save_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
} else if regs_type[i] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
{
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if regs_type[i + 1] == RegType::Object {
|
||||||
|
save_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: (i + 1) as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: reg_save,
|
||||||
|
to: (i + 1) as u16,
|
||||||
|
});
|
||||||
|
} else if regs_type[i + 1] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
{
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: (i + 1) as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: (i + 1) as u16,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Last resort
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16))
|
||||||
|
&& !used_reg.contains(&((i + 1) as u16))
|
||||||
|
&& (regs_type[i] == RegType::Object
|
||||||
|
|| regs_type[i] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
|| regs_type[i] == RegType::Any
|
||||||
|
|| regs_type[i] == RegType::Undefined)
|
||||||
|
&& (regs_type[i + 1] == RegType::Object
|
||||||
|
|| regs_type[i + 1] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i + 1] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i + 1] == RegType::SecondWideScalar
|
||||||
|
|| regs_type[i] == RegType::Any
|
||||||
|
|| regs_type[i + 1] == RegType::Undefined)
|
||||||
|
{
|
||||||
|
self.array_val = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
used_reg.push((i + 1) as u16);
|
||||||
|
if regs_type[i] == RegType::Object {
|
||||||
|
save_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
} else if regs_type[i] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
|| regs_type[i] == RegType::Any
|
||||||
|
{
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if regs_type[i + 1] == RegType::Object {
|
||||||
|
save_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: (i + 1) as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: reg_save,
|
||||||
|
to: (i + 1) as u16,
|
||||||
|
});
|
||||||
|
} else if regs_type[i + 1] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
{
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: (i + 1) as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: (i + 1) as u16,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
bail!("Could not found enough usable registers to patch the method")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(reg_save) = self.array_index_save {
|
||||||
|
let mut found = false;
|
||||||
|
if reg_save <= 0b1111 {
|
||||||
|
// This should not happend, but who knows?
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16)) && regs_type[i] == RegType::SimpleScalar {
|
||||||
|
self.array_index = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16))
|
||||||
|
&& (regs_type[i] == RegType::Object
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
|| regs_type[i] == RegType::Undefined)
|
||||||
|
{
|
||||||
|
self.array_index = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
if regs_type[i] == RegType::Object {
|
||||||
|
save_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
} else if regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
{
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Last resort
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16)) && regs_type[i] == RegType::Any {
|
||||||
|
self.array_index = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
bail!("Could not found enough usable registers to patch the method")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(reg_save) = self.array_save {
|
||||||
|
let mut found = false;
|
||||||
|
if reg_save <= 0b1111 {
|
||||||
|
// This should not happend, but who knows?
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16)) && regs_type[i] == RegType::Object {
|
||||||
|
self.array = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
save_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::MoveObject {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16))
|
||||||
|
&& (regs_type[i] == RegType::SimpleScalar
|
||||||
|
|| regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
|| regs_type[i] == RegType::Undefined)
|
||||||
|
{
|
||||||
|
self.array = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
if regs_type[i] == RegType::FirstWideScalar
|
||||||
|
|| regs_type[i] == RegType::SecondWideScalar
|
||||||
|
{
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Last resort
|
||||||
|
if !found {
|
||||||
|
for i in 0..15 {
|
||||||
|
if i >= regs_type.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if !used_reg.contains(&(i as u16)) && regs_type[i] == RegType::Any {
|
||||||
|
self.array = i as u8;
|
||||||
|
used_reg.push(i as u16);
|
||||||
|
save_reg_insns.push(Instruction::Move {
|
||||||
|
from: i as u16,
|
||||||
|
to: reg_save,
|
||||||
|
});
|
||||||
|
restore_reg_insns.push(Instruction::Move {
|
||||||
|
from: reg_save,
|
||||||
|
to: i as u16,
|
||||||
|
});
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
bail!("Could not found enough usable registers to patch the method")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok((save_reg_insns, restore_reg_insns))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static MTH_INVOKE: LazyLock<IdMethod> = LazyLock::new(|| {
|
static MTH_INVOKE: LazyLock<IdMethod> = LazyLock::new(|| {
|
||||||
IdMethod::from_smali(
|
IdMethod::from_smali(
|
||||||
"Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
|
"Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
|
||||||
|
|
@ -264,20 +645,42 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
|
||||||
|
|
||||||
let code = meth
|
let code = meth
|
||||||
.code
|
.code
|
||||||
.as_mut()
|
.as_ref()
|
||||||
.with_context(|| format!("Code not found in {}", meth.descriptor.__str__()))?;
|
.with_context(|| format!("Code not found in {}", meth.descriptor.__str__()))?;
|
||||||
// TODO
|
|
||||||
if code.registers_size + RegistersInfo::NB_U8_REG > u8::MAX as u16 {
|
// Get the available registers at the method level
|
||||||
bail!("To many registers");
|
let mut register_info = RegistersInfo::default();
|
||||||
|
// register_info.array_val is a wide reg, so need at least 0b1110 and 0b1111
|
||||||
|
if code.registers_size < 0b1111 {
|
||||||
|
register_info.array_val = code.registers_size as u8;
|
||||||
|
} else {
|
||||||
|
register_info.array_val = 0;
|
||||||
|
register_info.array_val_save = Some(code.registers_size);
|
||||||
}
|
}
|
||||||
let mut register_info = RegistersInfo {
|
if code.registers_size + 2 <= 0b1111 {
|
||||||
array_index: code.registers_size as u8,
|
register_info.array_index = (code.registers_size + 2) as u8;
|
||||||
array_val: (code.registers_size + 1) as u8,
|
} else {
|
||||||
array: (code.registers_size + 3) as u8,
|
register_info.array_index = 0;
|
||||||
//array: 0,
|
register_info.array_index_save = Some(code.registers_size + 2);
|
||||||
first_arg: code.registers_size + 4,
|
}
|
||||||
nb_arg_reg: 0,
|
if code.registers_size + 3 <= 0b1111 {
|
||||||
|
register_info.array = (code.registers_size + 3) as u8;
|
||||||
|
} else {
|
||||||
|
register_info.array = 0;
|
||||||
|
register_info.array_save = Some(code.registers_size + 3);
|
||||||
|
}
|
||||||
|
register_info.first_arg = code.registers_size + 4;
|
||||||
|
register_info.nb_arg_reg = 0;
|
||||||
|
|
||||||
|
let regs_type = if register_info.array_val_save.is_none()
|
||||||
|
|| register_info.array_index_save.is_none()
|
||||||
|
|| register_info.array_save.is_none()
|
||||||
|
{
|
||||||
|
Some(meth.get_cfg()?.get_reg_types())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut new_insns = vec![];
|
let mut new_insns = vec![];
|
||||||
let mut iter = code.insns.iter();
|
let mut iter = code.insns.iter();
|
||||||
let mut current_addr_label: Option<String> = None;
|
let mut current_addr_label: Option<String> = None;
|
||||||
|
|
@ -301,6 +704,47 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
|
||||||
} else {
|
} else {
|
||||||
panic!("Should not happen!")
|
panic!("Should not happen!")
|
||||||
};
|
};
|
||||||
|
let mut restore_reg = vec![];
|
||||||
|
if let Some(regs_type) = regs_type.as_ref() {
|
||||||
|
if (method == &*MTH_INVOKE && invoke_data.contains_key(addr_label))
|
||||||
|
|| (method == &*CLASS_NEW_INST
|
||||||
|
&& class_new_inst_data.contains_key(addr_label))
|
||||||
|
|| (method == &*CNSTR_NEW_INST
|
||||||
|
&& cnstr_new_inst_data.contains_key(addr_label))
|
||||||
|
{
|
||||||
|
let regs_type = regs_type.get(addr_label).unwrap();
|
||||||
|
let mut used_reg = args.clone();
|
||||||
|
match move_ret {
|
||||||
|
Some(Instruction::MoveResult { to }) => used_reg.push(to as u16),
|
||||||
|
Some(Instruction::MoveResultObject { to }) => used_reg.push(to as u16),
|
||||||
|
Some(Instruction::MoveResultWide { to }) => used_reg.push(to as u16),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
match register_info.tmp_reserve_reg(&used_reg, regs_type) {
|
||||||
|
Ok((mut save_insns, restore_insns)) => {
|
||||||
|
restore_reg = restore_insns;
|
||||||
|
new_insns.append(&mut save_insns);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
"Failed to instrument reflection in {} at {}: {}",
|
||||||
|
method.__str__(),
|
||||||
|
addr_label,
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
new_insns.push(ins.clone());
|
||||||
|
if let Some(move_ret) = move_ret.as_ref() {
|
||||||
|
for ins in pseudo_insns.iter() {
|
||||||
|
new_insns.push(ins.clone());
|
||||||
|
}
|
||||||
|
new_insns.push(move_ret.clone());
|
||||||
|
}
|
||||||
|
current_addr_label = None;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO: recover from failure
|
// TODO: recover from failure
|
||||||
if method == &*MTH_INVOKE {
|
if method == &*MTH_INVOKE {
|
||||||
for ref_data in invoke_data.get(addr_label).unwrap_or(&vec![]) {
|
for ref_data in invoke_data.get(addr_label).unwrap_or(&vec![]) {
|
||||||
|
|
@ -350,6 +794,7 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
|
||||||
}
|
}
|
||||||
let end_label = Instruction::Label { name: end_label };
|
let end_label = Instruction::Label { name: end_label };
|
||||||
new_insns.push(end_label.clone());
|
new_insns.push(end_label.clone());
|
||||||
|
new_insns.append(&mut restore_reg);
|
||||||
current_addr_label = None;
|
current_addr_label = None;
|
||||||
}
|
}
|
||||||
Instruction::Label { name } if name.starts_with("THESEUS_ADDR_") => {
|
Instruction::Label { name } if name.starts_with("THESEUS_ADDR_") => {
|
||||||
|
|
@ -364,6 +809,11 @@ pub fn transform_method(meth: &mut Method, ref_data: &ReflectionData) -> Result<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let code = meth
|
||||||
|
.code
|
||||||
|
.as_mut()
|
||||||
|
.with_context(|| format!("Code not found in {}", meth.descriptor.__str__()))?;
|
||||||
|
|
||||||
code.insns = vec![];
|
code.insns = vec![];
|
||||||
// Start the method by moving the parameter to their registers pre-transformation.
|
// Start the method by moving the parameter to their registers pre-transformation.
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
@ -486,7 +936,7 @@ fn get_invoke_block(
|
||||||
});
|
});
|
||||||
insns.append(&mut get_args_from_obj_arr(
|
insns.append(&mut get_args_from_obj_arr(
|
||||||
&ref_data.method.proto.get_parameters(),
|
&ref_data.method.proto.get_parameters(),
|
||||||
arg_arr as u8, // TODO
|
arg_arr,
|
||||||
reg_inf.first_arg + 1,
|
reg_inf.first_arg + 1,
|
||||||
reg_inf,
|
reg_inf,
|
||||||
));
|
));
|
||||||
|
|
@ -598,14 +1048,28 @@ pub fn get_scalar_to_obj_method(scalar_ty: &IdType) -> Result<IdMethod> {
|
||||||
/// types consecutive registers starting at `first_arg_reg`.
|
/// types consecutive registers starting at `first_arg_reg`.
|
||||||
/// `first_arg_reg` sould be `reg_inf.first_arg` or `reg_inf.first_arg+1` depending on if this
|
/// `first_arg_reg` sould be `reg_inf.first_arg` or `reg_inf.first_arg+1` depending on if this
|
||||||
/// is for a static or virtual call.
|
/// is for a static or virtual call.
|
||||||
pub fn get_args_from_obj_arr(
|
fn get_args_from_obj_arr(
|
||||||
params: &[IdType],
|
params: &[IdType],
|
||||||
array_reg: u8,
|
array_reg: u16,
|
||||||
first_arg_reg: u16,
|
first_arg_reg: u16,
|
||||||
reg_inf: &mut RegistersInfo,
|
reg_inf: &mut RegistersInfo,
|
||||||
) -> Vec<Instruction> {
|
) -> Vec<Instruction> {
|
||||||
let mut insns = vec![];
|
let mut insns = vec![];
|
||||||
|
let mut restore_array = vec![];
|
||||||
let mut reg_count = 0;
|
let mut reg_count = 0;
|
||||||
|
let array_reg = if array_reg <= 0b1111 {
|
||||||
|
array_reg as u8
|
||||||
|
} else {
|
||||||
|
insns.push(Instruction::MoveObject {
|
||||||
|
from: array_reg,
|
||||||
|
to: reg_inf.array as u16,
|
||||||
|
});
|
||||||
|
restore_array.push(Instruction::MoveObject {
|
||||||
|
from: reg_inf.array as u16,
|
||||||
|
to: array_reg,
|
||||||
|
});
|
||||||
|
reg_inf.array
|
||||||
|
};
|
||||||
for (i, param) in params.iter().enumerate() {
|
for (i, param) in params.iter().enumerate() {
|
||||||
insns.push(Instruction::Const {
|
insns.push(Instruction::Const {
|
||||||
reg: reg_inf.array_index,
|
reg: reg_inf.array_index,
|
||||||
|
|
@ -654,6 +1118,7 @@ pub fn get_args_from_obj_arr(
|
||||||
reg_count += 1;
|
reg_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
insns.append(&mut restore_array);
|
||||||
insns
|
insns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -662,7 +1127,7 @@ pub fn get_args_from_obj_arr(
|
||||||
/// - `method_obj_reg`: the register containing the `java.lang.reflect.Method`
|
/// - `method_obj_reg`: the register containing the `java.lang.reflect.Method`
|
||||||
/// - `id_method`: the expected [`IdMethod`].
|
/// - `id_method`: the expected [`IdMethod`].
|
||||||
/// - `abort_label`: the label where to jump if the method does not match `id_method`.
|
/// - `abort_label`: the label where to jump if the method does not match `id_method`.
|
||||||
pub fn test_method(
|
fn test_method(
|
||||||
method_obj_reg: u16,
|
method_obj_reg: u16,
|
||||||
id_method: IdMethod,
|
id_method: IdMethod,
|
||||||
abort_label: String,
|
abort_label: String,
|
||||||
|
|
@ -818,14 +1283,25 @@ fn get_cnstr_new_inst_block(
|
||||||
);
|
);
|
||||||
insns.append(&mut get_args_from_obj_arr(
|
insns.append(&mut get_args_from_obj_arr(
|
||||||
&ref_data.constructor.proto.get_parameters(),
|
&ref_data.constructor.proto.get_parameters(),
|
||||||
arg_arr as u8, // TODO
|
arg_arr,
|
||||||
reg_inf.first_arg + 1,
|
reg_inf.first_arg + 1,
|
||||||
reg_inf,
|
reg_inf,
|
||||||
));
|
));
|
||||||
insns.push(Instruction::NewInstance {
|
if reg_inf.first_arg < u8::MAX as u16 {
|
||||||
reg: reg_inf.first_arg as u8,
|
insns.push(Instruction::NewInstance {
|
||||||
lit: ref_data.constructor.class_.clone(),
|
reg: reg_inf.first_arg as u8,
|
||||||
});
|
lit: ref_data.constructor.class_.clone(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
insns.push(Instruction::NewInstance {
|
||||||
|
reg: reg_inf.array_val,
|
||||||
|
lit: ref_data.constructor.class_.clone(),
|
||||||
|
});
|
||||||
|
insns.push(Instruction::MoveObject {
|
||||||
|
from: reg_inf.array_val as u16,
|
||||||
|
to: reg_inf.first_arg,
|
||||||
|
});
|
||||||
|
}
|
||||||
insns.push(Instruction::InvokeDirect {
|
insns.push(Instruction::InvokeDirect {
|
||||||
method: ref_data.constructor.clone(),
|
method: ref_data.constructor.clone(),
|
||||||
args: (reg_inf.first_arg..reg_inf.first_arg + nb_args as u16 + 1).collect(),
|
args: (reg_inf.first_arg..reg_inf.first_arg + nb_args as u16 + 1).collect(),
|
||||||
|
|
@ -848,7 +1324,7 @@ fn get_cnstr_new_inst_block(
|
||||||
/// - `method_obj_reg`: the register containing the `java.lang.reflect.Method`
|
/// - `method_obj_reg`: the register containing the `java.lang.reflect.Method`
|
||||||
/// - `id_method`: the expected [`IdMethod`].
|
/// - `id_method`: the expected [`IdMethod`].
|
||||||
/// - `abort_label`: the label where to jump if the method does not match `id_method`.
|
/// - `abort_label`: the label where to jump if the method does not match `id_method`.
|
||||||
pub fn test_cnstr(
|
fn test_cnstr(
|
||||||
cnst_reg: u16,
|
cnst_reg: u16,
|
||||||
id_method: IdMethod,
|
id_method: IdMethod,
|
||||||
abort_label: String,
|
abort_label: String,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue