Skip to content

Commit

Permalink
Merge branch 'develop-v0.3' of github.com:fugue-re/fugue-core into de…
Browse files Browse the repository at this point in the history
…velop-v0.3
  • Loading branch information
xorpse committed May 15, 2024
2 parents 7717aa4 + 009eacc commit a1746a3
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 0 deletions.
1 change: 1 addition & 0 deletions fugue-high/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ tempfile = "3"
thiserror = "1"
yaxpeax-arch = { version = "0.2", default-features = false }
yaxpeax-arm = "0.2"
yaxpeax-x86 = "1.2"

[dev-dependencies]
anyhow = "1"
Expand Down
94 changes: 94 additions & 0 deletions fugue-high/src/arch/aarch64.rs
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,
})
}
}
}
2 changes: 2 additions & 0 deletions fugue-high/src/arch/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod arm;
pub mod aarch64;
pub mod x86;
209 changes: 209 additions & 0 deletions fugue-high/src/arch/x86.rs
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(())
}
}
1 change: 1 addition & 0 deletions fugue-high/src/eval/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ mod test {
use super::*;

#[test]
#[ignore]
fn test_single_step() -> anyhow::Result<()> {
let lbuilder = LanguageBuilder::new("data")?;
let language = lbuilder.build("ARM:LE:32:v7", "default")?;
Expand Down
1 change: 1 addition & 0 deletions fugue-high/src/loader/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ mod test {
use crate::util::BytesOrMapping;

#[test]
#[ignore]
fn test_elf() -> Result<(), Box<dyn std::error::Error>> {
let lb = LanguageBuilder::new("data/processors")?;
let elf = Object::new(BytesOrMapping::from_file("tests/ls.elf")?)?;
Expand Down

0 comments on commit a1746a3

Please sign in to comment.