-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop-v0.3' of github.com:fugue-re/fugue-core into de…
…velop-v0.3
- Loading branch information
Showing
6 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
use std::cell::{Cell, RefCell}; | ||
|
||
use fugue_ir::disassembly::IRBuilderArena; | ||
use fugue_ir::Address; | ||
|
||
use thiserror::Error; | ||
|
||
use yaxpeax_arch::*; | ||
use yaxpeax_arm::armv8::a64::Opcode; | ||
|
||
pub use yaxpeax_arm::armv8::a64::{ | ||
DecodeError as AArch64DecoderError, InstDecoder as AArch64InstDecoder, Instruction as AArch64Instruction, | ||
}; | ||
|
||
use crate::ir::PCode; | ||
use crate::lifter::{InsnLifter, LiftedInsn, LiftedInsnProperties, Lifter}; | ||
|
||
pub struct AArch64InsnLifter { | ||
decoder: AArch64InstDecoder, | ||
} | ||
|
||
#[derive(Debug, Error)] | ||
pub enum AArch64LifterError { | ||
#[error(transparent)] | ||
Decoder(#[from] AArch64DecoderError), | ||
#[error(transparent)] | ||
Lifter(#[from] fugue_ir::error::Error), | ||
} | ||
|
||
impl AArch64InsnLifter { | ||
pub fn new() -> Self { | ||
Self::new_with(AArch64InstDecoder::default()) | ||
} | ||
|
||
pub fn new_with(decoder: AArch64InstDecoder) -> Self { | ||
Self { decoder } | ||
} | ||
} | ||
|
||
fn should_lift(insn: &AArch64Instruction) -> bool { | ||
match insn.opcode { | ||
Opcode::B | ||
| Opcode::BL | ||
| Opcode::CBZ | ||
| Opcode::CBNZ | ||
| Opcode::SVC => true, | ||
_ => false, | ||
} | ||
} | ||
|
||
impl<'a> InsnLifter<'a, AArch64Instruction> for AArch64InsnLifter { | ||
type Error = AArch64LifterError; | ||
|
||
fn properties<'b>( | ||
&mut self, | ||
lifter: &mut Lifter, | ||
irb: &'a IRBuilderArena, | ||
address: Address, | ||
bytes: &'b [u8], | ||
) -> Result<LiftedInsn<'a, 'b, AArch64Instruction>, Self::Error> { | ||
let mut reader = yaxpeax_arch::U8Reader::new(bytes); | ||
let insn = self.decoder.decode(&mut reader)?; | ||
let size = insn.len().to_const() as u8; | ||
|
||
if should_lift(&insn) { | ||
let PCode { | ||
address, | ||
operations, | ||
delay_slots, | ||
length, | ||
} = lifter.lift(irb, address, bytes)?; | ||
|
||
Ok(LiftedInsn { | ||
address, | ||
bytes, | ||
properties: Cell::new(LiftedInsnProperties::default()), | ||
operations: RefCell::new(Some(operations)), | ||
delay_slots, | ||
length, | ||
data: insn, | ||
}) | ||
} else { | ||
Ok(LiftedInsn { | ||
address, | ||
bytes, | ||
properties: Cell::new(LiftedInsnProperties::default()), | ||
operations: RefCell::new(None), | ||
delay_slots: 0, | ||
length: size, | ||
data: insn, | ||
}) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
pub mod arm; | ||
pub mod aarch64; | ||
pub mod x86; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
use std::cell::{Cell, RefCell}; | ||
|
||
use fugue_ir::disassembly::IRBuilderArena; | ||
use fugue_ir::Address; | ||
|
||
use thiserror::Error; | ||
|
||
use yaxpeax_arch::*; | ||
pub use yaxpeax_x86::{x86_32, x86_64}; | ||
|
||
pub use yaxpeax_x86::amd64::{ | ||
DecodeError as X86_64DecoderError, InstDecoder as X86_64InstDecoder, | ||
Instruction as X86_64Instruction, | ||
}; | ||
pub use yaxpeax_x86::protected_mode::{ | ||
DecodeError as X86_32DecoderError, InstDecoder as X86_32InstDecoder, | ||
Instruction as X86_32Instruction, | ||
}; | ||
|
||
use crate::ir::PCode; | ||
use crate::lifter::{InsnLifter, LiftedInsn, LiftedInsnProperties, Lifter}; | ||
|
||
pub trait X86Arch: Arch { | ||
fn should_lift(insn: &Self::Instruction) -> bool; | ||
} | ||
|
||
impl X86Arch for x86_32 { | ||
fn should_lift(insn: &Self::Instruction) -> bool { | ||
use yaxpeax_x86::protected_mode::Opcode; | ||
|
||
return match insn.opcode() { | ||
Opcode::JO | | ||
Opcode::JB | | ||
Opcode::JZ | | ||
Opcode::JA | | ||
Opcode::JS | | ||
Opcode::JP | | ||
Opcode::JL | | ||
Opcode::JG | | ||
Opcode::JMP | | ||
Opcode::JNO | | ||
Opcode::JNB | | ||
Opcode::JNZ | | ||
Opcode::JNA | | ||
Opcode::JNS | | ||
Opcode::JNP | | ||
Opcode::JGE | | ||
Opcode::JLE | | ||
Opcode::JMPF | | ||
Opcode::JMPE | | ||
Opcode::JECXZ => true, | ||
Opcode::CALL | Opcode::CALLF => true, | ||
Opcode::RETF | Opcode::RETURN => true, | ||
_ => false, | ||
} | ||
} | ||
} | ||
|
||
impl X86Arch for x86_64 { | ||
fn should_lift(insn: &Self::Instruction) -> bool { | ||
use yaxpeax_x86::amd64::Opcode; | ||
|
||
return match insn.opcode() { | ||
Opcode::JO | | ||
Opcode::JB | | ||
Opcode::JZ | | ||
Opcode::JA | | ||
Opcode::JS | | ||
Opcode::JP | | ||
Opcode::JL | | ||
Opcode::JG | | ||
Opcode::JMP | | ||
Opcode::JNO | | ||
Opcode::JNB | | ||
Opcode::JNZ | | ||
Opcode::JNA | | ||
Opcode::JNS | | ||
Opcode::JNP | | ||
Opcode::JGE | | ||
Opcode::JLE | | ||
Opcode::JMPF | | ||
Opcode::JMPE => true, | ||
Opcode::CALL | Opcode::CALLF => true, | ||
Opcode::RETF | Opcode::RETURN => true, | ||
_ => false, | ||
} | ||
} | ||
} | ||
|
||
pub struct X86InsnLifter<D> | ||
where | ||
D: X86Arch, | ||
{ | ||
decoder: D::Decoder, | ||
} | ||
|
||
#[derive(Debug, Error)] | ||
pub enum X86LifterError { | ||
#[error(transparent)] | ||
Decoder(anyhow::Error), | ||
#[error(transparent)] | ||
Lifter(#[from] fugue_ir::error::Error), | ||
} | ||
|
||
impl X86LifterError { | ||
pub fn decoder<E>(e: E) -> Self | ||
where | ||
E: std::error::Error + Send + Sync + 'static, | ||
{ | ||
Self::Decoder(e.into()) | ||
} | ||
} | ||
|
||
impl<D> X86InsnLifter<D> | ||
where | ||
D: X86Arch, | ||
{ | ||
pub fn new() -> X86InsnLifter<D> { | ||
Self::new_with(D::Decoder::default()) | ||
} | ||
|
||
pub fn new_32() -> X86InsnLifter<x86_32> { | ||
X86InsnLifter::new_with(X86_32InstDecoder::default()) | ||
} | ||
|
||
pub fn new_64() -> X86InsnLifter<x86_64> { | ||
X86InsnLifter::new_with(X86_64InstDecoder::default()) | ||
} | ||
|
||
pub fn new_with(decoder: D::Decoder) -> Self { | ||
Self { decoder } | ||
} | ||
} | ||
|
||
impl<'a, D> InsnLifter<'a, D::Instruction> for X86InsnLifter<D> | ||
where | ||
D: X86Arch, | ||
D::Instruction: 'a, | ||
for<'b> U8Reader<'b>: Reader<D::Address, D::Word>, | ||
<D::Address as AddressBase>::Diff: TryInto<u8>, | ||
<<D::Address as AddressBase>::Diff as TryInto<u8>>::Error: | ||
std::error::Error + Send + Sync + 'static, | ||
{ | ||
type Error = X86LifterError; | ||
|
||
fn properties<'b>( | ||
&mut self, | ||
lifter: &mut Lifter, | ||
irb: &'a IRBuilderArena, | ||
address: Address, | ||
bytes: &'b [u8], | ||
) -> Result<LiftedInsn<'a, 'b, D::Instruction>, Self::Error> { | ||
let mut reader = yaxpeax_arch::U8Reader::new(bytes); | ||
|
||
let insn = self | ||
.decoder | ||
.decode(&mut reader) | ||
.map_err(X86LifterError::decoder)?; | ||
|
||
let size = insn | ||
.len() | ||
.to_const() | ||
.try_into() | ||
.map_err(X86LifterError::decoder)?; | ||
|
||
if D::should_lift(&insn) { | ||
let PCode { | ||
address, | ||
operations, | ||
delay_slots, | ||
length, | ||
} = lifter.lift(irb, address, bytes)?; | ||
|
||
Ok(LiftedInsn { | ||
address, | ||
bytes, | ||
properties: Cell::new(LiftedInsnProperties::default()), | ||
operations: RefCell::new(Some(operations)), | ||
delay_slots, | ||
length, | ||
data: insn, | ||
}) | ||
} else { | ||
Ok(LiftedInsn { | ||
address, | ||
bytes, | ||
properties: Cell::new(LiftedInsnProperties::default()), | ||
operations: RefCell::new(None), | ||
delay_slots: 0, | ||
length: size, | ||
data: insn, | ||
}) | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
#[test] | ||
#[ignore] | ||
#[allow(unused)] | ||
fn test() -> anyhow::Result<()> { | ||
let mut t0 = X86InsnLifter::<x86_32>::new(); | ||
t0.properties(todo!(), todo!(), todo!(), todo!()); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters