Skip to content

Commit

Permalink
restructure; begin defining loader interface
Browse files Browse the repository at this point in the history
  • Loading branch information
xorpse committed May 15, 2024
1 parent 009eacc commit dbc6e0c
Show file tree
Hide file tree
Showing 27 changed files with 356 additions and 105 deletions.
42 changes: 26 additions & 16 deletions fugue-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
[package]
name = "fugue"
name = "fugue-core"
version = "0.3.0"
authors = ["Sam Thomas <st@xv.ax>", "Zitai Chen <zitaichen@outlook.com>"]
edition = "2021"
license = "MIT"
description = "A binary analysis framework written in Rust"
homepage = "https://fugue.re"

[features]
fp = ["fugue-fp"]
state = ["fugue-state"]

[dependencies]
fugue-arch = { path = "../fugue-arch", version = "0.3" }
fugue-bv = { path = "../fugue-bv", version = "0.3" }
fugue-bytes = { path = "../fugue-bytes", version = "0.3" }
fugue-high = { path = "../fugue-high", version = "0.3" }
fugue-fp = { path = "../fugue-fp", version = "0.3", optional = true }
fugue-ir = { path = "../fugue-ir", version = "0.3" }
fugue-state = { path = "../fugue-state", version = "0.3", optional = true }
anyhow = "1"
bitflags = "2"
fugue-arch = { version = "0.3", path = "../fugue-arch" }
fugue-bv = { version = "0.3", path = "../fugue-bv" }
fugue-bytes = { version = "0.3", path = "../fugue-bytes" }
fugue-ir = { version = "0.3", path = "../fugue-ir" }
gazebo = "0.8"
nom = "7"
memmap2 = "0.9"
object = "0.35"
ouroboros = "0.18"
regex = "1"
rustc-hash = "1.1"
serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
static_init = "1"
thiserror = "1"
yaxpeax-arch = { version = "0.2", default-features = false }
yaxpeax-arm = "0.2"
yaxpeax-x86 = "1.2"
uuid = "1"

[dev-dependencies]
anyhow = "1"
env_logger = "0.10"
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions fugue-core/src/attributes/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::borrow::Cow;

use gazebo::any::ProvidesStaticType;
use uuid::{uuid, Uuid};

use super::Attribute;

#[derive(ProvidesStaticType)]
pub struct CompilerConvention(Cow<'static, str>);

impl CompilerConvention {
pub fn new(convention: impl Into<Cow<'static, str>>) -> Self {
Self(convention.into())
}
}

impl AsRef<str> for CompilerConvention {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}

impl<'a> Attribute<'a> for CompilerConvention {
const UUID: Uuid = uuid!("9D5D5EFA-3985-45C5-B803-49217FE3184D");
}
62 changes: 62 additions & 0 deletions fugue-core/src/attributes/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::ops::Deref;

use rustc_hash::FxHashMap;
use uuid::Uuid;

pub use gazebo::any::{AnyLifetime, ProvidesStaticType};

pub mod common;
pub mod platform;

pub struct Attributes<'a> {
attrs: FxHashMap<Uuid, Box<dyn AnyLifetime<'a>>>,
}

pub trait Attribute<'a>: AnyLifetime<'a> {
const UUID: Uuid;
}

impl<'a> Attributes<'a> {
pub fn new() -> Self {
Self {
attrs: FxHashMap::default(),
}
}

pub fn set_attr<T>(&mut self, value: T)
where
T: Attribute<'a>,
{
self.attrs.insert(T::UUID, Box::new(value));
}

pub fn get_attr<T>(&self) -> Option<&T>
where
T: Attribute<'a>,
{
self.attrs.get(&T::UUID).and_then(|v| v.downcast_ref())
}

pub fn get_attr_as<T, U>(&self) -> Option<&U>
where
T: Attribute<'a> + AsRef<U>,
U: ?Sized,
{
self.get_attr::<T>().map(T::as_ref)
}

pub fn get_attr_as_deref<T, U>(&self) -> Option<&U>
where
T: Attribute<'a> + Deref<Target = U>,
U: ?Sized,
{
self.get_attr::<T>().map(T::deref)
}

pub fn get_attr_mut<T>(&mut self) -> Option<&mut T>
where
T: Attribute<'a>,
{
self.attrs.get_mut(&T::UUID).and_then(|v| v.downcast_mut())
}
}
1 change: 1 addition & 0 deletions fugue-core/src/attributes/platform/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// pub mod uefi;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
21 changes: 10 additions & 11 deletions fugue-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#[cfg(feature = "fp")]
pub use fugue_fp as fp;

#[cfg(feature = "state")]
pub use fugue_state as state;

pub use fugue_arch as arch;
pub use fugue_bv as bv;
pub use fugue_bytes as bytes;
pub use fugue_high as high;
pub use fugue_ir as ir;
pub mod arch;
pub mod attributes;
pub mod eval;
pub mod icfg;
pub mod ir;
pub mod language;
pub mod lifter;
pub mod loader;
pub mod prelude;
pub mod util;
File renamed without changes.
127 changes: 127 additions & 0 deletions fugue-core/src/loader/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use std::borrow::Cow;
use std::fmt::{Debug, Display};
use std::ops::Deref;

use fugue_bytes::Endian;
use fugue_ir::Address;
use thiserror::Error;

use crate::attributes::common::CompilerConvention;
use crate::attributes::Attribute;
use crate::language::{Language, LanguageBuilder, LanguageBuilderError};
use crate::util::BytesOrMapping;

pub mod object;

pub use self::object::Object;

#[derive(Debug, Error)]
pub enum LoaderError {
#[error("cannot load object: {0}")]
Format(anyhow::Error),
#[error(transparent)]
Language(#[from] LanguageBuilderError),
}

impl LoaderError {
pub fn format<E>(e: E) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Self::Format(e.into())
}

pub fn format_with<M>(m: M) -> Self
where
M: Debug + Display + Send + Sync + 'static,
{
Self::Format(anyhow::Error::msg(m))
}
}

pub trait Loadable<'a>: Sized {
fn new(data: impl Into<BytesOrMapping<'a>>) -> Result<Self, LoaderError>;

fn get_attr<T>(&self) -> Option<&T>
where
T: Attribute<'a>;

fn get_attr_as<'slf, T, U>(&'slf self) -> Option<&'slf U>
where
T: Attribute<'a> + AsRef<U> + 'slf,
U: ?Sized,
{
self.get_attr::<T>().map(T::as_ref)
}

fn get_attr_as_deref<'slf, T, U>(&'slf self) -> Option<&'slf U>
where
T: Attribute<'a> + Deref<Target = U> + 'slf,
U: ?Sized,
{
self.get_attr::<T>().map(T::deref)
}

fn set_attr<T>(&mut self, attr: T)
where
T: Attribute<'a>;

fn endian(&self) -> Endian;

fn language(&self, builder: &LanguageBuilder) -> Result<Language, LoaderError> {
let convention = self
.get_attr_as::<CompilerConvention, _>()
.unwrap_or("default");
self.language_with(builder, convention)
}

fn language_with(
&self,
builder: &LanguageBuilder,
convention: impl AsRef<str>,
) -> Result<Language, LoaderError>;

fn entry(&self) -> Option<Address> {
None
}

fn segments<'slf>(&'slf self) -> impl Iterator<Item = LoadableSegment<'slf>>;
}

pub struct LoadableSegment<'a> {
addr: Address,
data: Cow<'a, [u8]>,
}

impl<'a> From<Vec<u8>> for LoadableSegment<'a> {
fn from(value: Vec<u8>) -> Self {
Self::new(0u32, value)
}
}

impl<'a> From<&'a [u8]> for LoadableSegment<'a> {
fn from(value: &'a [u8]) -> Self {
Self::new(0u32, value)
}
}

impl<'a> LoadableSegment<'a> {
pub fn new(addr: impl Into<Address>, data: impl Into<Cow<'a, [u8]>>) -> Self {
Self {
addr: addr.into(),
data: data.into(),
}
}

pub fn address(&self) -> Address {
self.addr
}

pub fn data(&self) -> &[u8] {
self.data.as_ref()
}

pub fn into_parts(self) -> (Address, Cow<'a, [u8]>) {
(self.addr, self.data)
}
}
Loading

0 comments on commit dbc6e0c

Please sign in to comment.