Skip to content

Commit

Permalink
Major code refactoring with clippy.
Browse files Browse the repository at this point in the history
  • Loading branch information
EgeBalci committed Jul 3, 2024
1 parent 1b3cb03 commit 2f819ce
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 314 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
name = "deoptimizer"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
license-file = "LICENSE"
license = "MIT"
# license-file = "LICENSE"
readme = "README.md"
repository = "https://github.com/EgeBalci/deoptimizer"
authors = ["Ege BALCI <[email protected]>"]
Expand Down
8 changes: 4 additions & 4 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub fn parse_options() -> Result<Options, ArgParseError> {
// let mut opts: Options = argh::from_env();
let mut opts = Options::parse();
if opts.file.is_empty() {
print!("\n");
println!();
error!("The '-f' parameter is mandatory.\n");
Options::command().print_help()?;
process::exit(0x01);
Expand Down Expand Up @@ -120,11 +120,11 @@ pub fn parse_options() -> Result<Options, ArgParseError> {
}

pub fn parse_offset(offsets: &str) -> Result<(u32, u32), ArgParseError> {
if offsets.matches("-").count() != 1 {
if offsets.matches('-').count() != 1 {
return Err(ArgParseError::InvalidOffsetValues);
}
let mut off: Vec<u32> = Vec::new();
for part in offsets.split("-") {
for part in offsets.split('-') {
if part.starts_with("0x") {
off.push(u32::from_str_radix(part.trim_start_matches("0x"), 16)?)
} else {
Expand Down Expand Up @@ -201,5 +201,5 @@ pub fn print_summary(opts: &Options) {
opts.transforms,
" ".repeat(wspace - opts.transforms.len())
);
print!("\n");
println!();
}
50 changes: 22 additions & 28 deletions src/x86_64/deoptimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,31 @@ use crate::x86_64::*;
use bitflags::bitflags;
use iced_x86::code_asm::*;
use iced_x86::*;
use log::{debug, error, info, trace, warn};
use rand::{seq::SliceRandom, Rng};
use log::{error, info, trace, warn};
use rand::Rng;
use std::collections::HashMap;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum DeoptimizerError {
// #[error("Instruction with unexpected operand count.")]
// UnexpectedOperandCount,
// #[error("Given instruction not found in code map.")]
// InstructionNotFound,
// #[error("Code analysis results are not found.")]
// MissingCodeAnalysis,
// #[error("Near branch value too large.")]
// NearBranchTooBig,
// #[error("Unexpected memory size given.")]
// UnexpectedMemorySize,
// #[error("Offset skipping failed!")]
// OffsetSkipFail,
#[error("Invalid formatter syntax.")]
InvalidSyntax,
#[error("Invalid processor mode(bitness). (16/32/64 accepted)")]
InvalidProcessorMode,
#[error("Instruction with unexpected operand count.")]
UnexpectedOperandCount,
#[error("All available instruction transform gadgets failed.")]
AllTransformsFailed,
#[error("Given instruction not found in code map.")]
InstructionNotFound,
#[error("Code analysis results are not found.")]
MissingCodeAnalysis,
#[error("Near branch value too large.")]
NearBranchTooBig,
#[error("Far branch value too large.")]
FarBranchTooBig,
#[error("Found invalid instruction.")]
Expand All @@ -31,8 +35,6 @@ pub enum DeoptimizerError {
BracnhTargetNotFound,
#[error("This transform not possible for given instruction.")]
TransformNotPossible,
#[error("Unexpected memory size given.")]
UnexpectedMemorySize,
#[error("Unexpected register size given.")]
UnexpectedRegisterSize,
#[error("Unexpected operand type encountered.")]
Expand All @@ -45,8 +47,6 @@ pub enum DeoptimizerError {
TransposeFailed,
#[error("Invalid transform gadget.")]
InvalidTransformGadget,
#[error("Offset skipping failed!")]
OffsetSkipFail,
#[error("Instruction encoding failed: {0}")]
EncodingFail(#[from] IcedError),
}
Expand All @@ -58,6 +58,7 @@ enum AssemblySyntax {
Intel,
Gas,
}

bitflags! {
#[derive(Clone, Copy, Debug,PartialEq,Eq, Hash)]
pub struct AvailableTransforms: u8 {
Expand Down Expand Up @@ -154,8 +155,8 @@ impl Deoptimizer {

pub fn set_transform_gadgets(&mut self, transforms: String) -> Result<(), DeoptimizerError> {
let mut selected_transforms = AvailableTransforms::None;
let trs = transforms.split(",");
for (_i, t) in trs.enumerate() {
let trs = transforms.split(',');
for t in trs {
match t.to_uppercase().as_str() {
"AP" => selected_transforms |= AvailableTransforms::ArithmeticPartitioning,
"LI" => selected_transforms |= AvailableTransforms::LogicalInverse,
Expand All @@ -182,9 +183,7 @@ impl Deoptimizer {
}

pub fn set_skipped_offsets(&mut self, skipped: Vec<(u32, u32)>) {
if skipped.len() > 0 {
self.skipped_offsets = Some(skipped);
}
self.skipped_offsets = Some(skipped);
}

fn is_offset_skipped(&self, offset: u32) -> bool {
Expand Down Expand Up @@ -234,7 +233,7 @@ impl Deoptimizer {
let mut decoder = Decoder::with_ip(bitness, bytes, start_addr, DecoderOptions::NONE);
let replaced_bytes: Vec<u8>;
if self.skipped_offsets.is_some() {
replaced_bytes = self.replace_skipped_offsets(&bytes, 0x90)?;
replaced_bytes = self.replace_skipped_offsets(bytes, 0x90)?;
decoder = Decoder::with_ip(bitness, &replaced_bytes, start_addr, DecoderOptions::NONE);
}

Expand Down Expand Up @@ -285,7 +284,7 @@ impl Deoptimizer {
}

for bt in branch_targets.iter() {
if !known_addr_table.contains(&bt) {
if !known_addr_table.contains(bt) {
warn!(
"Branch target 0x{:016X} is outside the known address sapce!",
bt
Expand Down Expand Up @@ -461,12 +460,7 @@ impl Deoptimizer {
if acode.is_branch_target(inst.ip()) {
ip_to_index_table.insert(inst.ip(), result.len());
}
match Deoptimizer::apply_transform(
acode.bitness,
&inst,
self.freq,
self.transforms.clone(),
) {
match Deoptimizer::apply_transform(acode.bitness, &inst, self.freq, self.transforms) {
Ok(dinst) => {
result = [result, dinst.clone()].concat();
print_inst_diff(&inst, dinst);
Expand Down Expand Up @@ -507,7 +501,7 @@ impl Deoptimizer {
result[*idx]
);
result[i] = set_branch_target(
&mut result[i].clone(),
&result[i].clone(),
result[*idx].ip(),
acode.bitness,
)?;
Expand Down
143 changes: 68 additions & 75 deletions src/x86_64/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn random_immediate_value(kind: OpKind) -> Result<u64, DeoptimizerError> {
})
}

pub fn adjust_instruction_addrs(code: &mut Vec<Instruction>, start_addr: u64) {
pub fn adjust_instruction_addrs(code: &mut [Instruction], start_addr: u64) {
let mut new_ip = start_addr;
for inst in code.iter_mut() {
inst.set_ip(new_ip);
Expand Down Expand Up @@ -61,35 +61,35 @@ pub fn get_instruction_bytes(bitness: u32, insts: Vec<Instruction>) -> Result<Ve
Ok(buffer)
}

pub fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
haystack
.windows(needle.len())
.position(|window| window == needle)
}

pub fn generate_random_instructions(size: usize) -> Vec<u8> {
let small_mnemonics = [
0x90, // nop
0xc3, // ret
0xf1, // int1
0xf4, // hlt
0xf5, // cmc
0xf8, // clc
0xfa, // cli
0xf9, // stc
0xfb, // sti
0xfc, // cld
]
.to_vec();
let mut output = Vec::new();
for _ in 0..size {
output.push(*small_mnemonics.choose(&mut rand::thread_rng()).unwrap() as u8)
}
output
}
// pub fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
// haystack
// .windows(needle.len())
// .position(|window| window == needle)
// }
//
// pub fn generate_random_instructions(size: usize) -> Vec<u8> {
// let small_mnemonics = [
// 0x90, // nop
// 0xc3, // ret
// 0xf1, // int1
// 0xf4, // hlt
// 0xf5, // cmc
// 0xf8, // clc
// 0xfa, // cli
// 0xf9, // stc
// 0xfb, // sti
// 0xfc, // cld
// ]
// .to_vec();
// let mut output = Vec::new();
// for _ in 0..size {
// output.push(*small_mnemonics.choose(&mut rand::thread_rng()).unwrap() as u8)
// }
// output
// }

pub fn print_inst_diff(inst: &Instruction, dinst: Vec<Instruction>) {
if log::max_level() <= log::Level::Info || dinst.len() == 0 {
if log::max_level() <= log::Level::Info || dinst.is_empty() {
return;
}
let inst_column_len = 48;
Expand Down Expand Up @@ -119,18 +119,12 @@ pub fn print_inst_diff(inst: &Instruction, dinst: Vec<Instruction>) {
}
} else {
println!(
"{:016X}:\t{}|\t{}",
"{:016X}:\t{}{}|\t{}{}",
inst.ip(),
format!(
"{}{}",
inst_str.blue(),
" ".repeat(inst_column_len - inst_str.len())
),
format!(
"{}{}",
inst_str.blue(),
" ".repeat(inst_column_len - inst_str.len())
),
inst_str.blue(),
" ".repeat(inst_column_len - inst_str.len()),
inst_str.blue(),
" ".repeat(inst_column_len - inst_str.len()),
);
}
}
Expand Down Expand Up @@ -189,18 +183,18 @@ pub fn transpose_fixed_register_operand(inst: &mut Instruction) -> Result<(), De
// }
// }

pub fn get_immediate_indexes(inst: &Instruction) -> Option<Vec<u32>> {
let mut indexes = Vec::new();
for i in 0..inst.op_count() {
if is_immediate_operand(inst.op_kind(i)) {
indexes.push(i);
}
}
if indexes.len() == 0 {
return None;
}
Some(indexes)
}
// pub fn get_immediate_indexes(inst: &Instruction) -> Option<Vec<u32>> {
// let mut indexes = Vec::new();
// for i in 0..inst.op_count() {
// if is_immediate_operand(inst.op_kind(i)) {
// indexes.push(i);
// }
// }
// if indexes.len() == 0 {
// return None;
// }
// Some(indexes)
// }

pub fn get_stack_pointer_register(bitness: u32) -> Result<Register, DeoptimizerError> {
Ok(match bitness {
Expand Down Expand Up @@ -234,25 +228,25 @@ pub fn to_db_mnemonic(bytes: &[u8]) -> String {
db_inst.trim_end_matches(", ").to_string()
}

pub fn get_register_save_seq(
bitness: u32,
reg: Register,
) -> Result<(Instruction, Instruction), DeoptimizerError> {
let mut full_reg = reg.full_register();
if bitness != 64 {
full_reg = reg.full_register32();
}
let (c1, c2) = match bitness {
16 => (Code::Push_r16, Code::Pop_r16),
32 => (Code::Push_r32, Code::Pop_r32),
64 => (Code::Push_r64, Code::Pop_r64),
_ => return Err(DeoptimizerError::InvalidProcessorMode),
};
Ok((
Instruction::with1(c1, full_reg)?,
Instruction::with1(c2, full_reg)?,
))
}
// pub fn get_register_save_seq(
// bitness: u32,
// reg: Register,
// ) -> Result<(Instruction, Instruction), DeoptimizerError> {
// let mut full_reg = reg.full_register();
// if bitness != 64 {
// full_reg = reg.full_register32();
// }
// let (c1, c2) = match bitness {
// 16 => (Code::Push_r16, Code::Pop_r16),
// 32 => (Code::Push_r32, Code::Pop_r32),
// 64 => (Code::Push_r64, Code::Pop_r64),
// _ => return Err(DeoptimizerError::InvalidProcessorMode),
// };
// Ok((
// Instruction::with1(c1, full_reg)?,
// Instruction::with1(c2, full_reg)?,
// ))
// }

pub fn get_random_register_value(reg: Register) -> u64 {
let mut rng = rand::thread_rng();
Expand Down Expand Up @@ -288,8 +282,7 @@ pub fn set_branch_target(
bt: u64,
bitness: u32,
) -> Result<Instruction, DeoptimizerError> {
let mut my_inst = inst.clone();

let mut my_inst = *inst;
if matches!(inst.op0_kind(), OpKind::FarBranch16 | OpKind::FarBranch32) {
if bt < u16::MAX as u64 {
my_inst.set_op0_kind(OpKind::FarBranch16);
Expand Down Expand Up @@ -407,15 +400,15 @@ pub fn get_random_gp_register(
let index = shuffed_regs.iter().position(|x| {
x.full_register() == ex.register().full_register() || x == &ex.register()
});
if index.is_some() {
shuffed_regs.remove(index.unwrap());
if let Some(idx) = index {
shuffed_regs.remove(idx);
}
}
}

for reg in shuffed_regs {
let reg_str = format!("{:?}", reg);
let is_extended = reg_str.contains("R") || reg_str.contains("IL") || reg_str.contains("PL");
let is_extended = reg_str.contains('R') || reg_str.contains("IL") || reg_str.contains("PL");
if is_extended == extended {
return Ok(reg);
}
Expand Down
Loading

0 comments on commit 2f819ce

Please sign in to comment.