add Python module

This commit is contained in:
Richard Patel 2021-08-17 00:40:13 +02:00
parent ea6545f7e3
commit 66b8d92934
11 changed files with 466 additions and 18 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
.idea/
.DS_Store
*.profraw
env/
lib/

260
Cargo.lock generated
View File

@ -8,12 +8,28 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "ctor"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "getrandom"
version = "0.1.16"
@ -25,6 +41,17 @@ dependencies = [
"wasi",
]
[[package]]
name = "ghost"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -34,12 +61,75 @@ dependencies = [
"libc",
]
[[package]]
name = "indoc"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
dependencies = [
"indoc-impl",
"proc-macro-hack",
]
[[package]]
name = "indoc-impl"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"syn",
"unindent",
]
[[package]]
name = "instant"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
dependencies = [
"cfg-if",
]
[[package]]
name = "inventory"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f"
dependencies = [
"ctor",
"ghost",
"inventory-impl",
]
[[package]]
name = "inventory-impl"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "libc"
version = "0.2.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765"
[[package]]
name = "lock_api"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
dependencies = [
"scopeguard",
]
[[package]]
name = "num-traits"
version = "0.2.14"
@ -59,9 +149,59 @@ dependencies = [
"libc",
]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "parking_lot"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "paste"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
dependencies = [
"paste-impl",
"proc-macro-hack",
]
[[package]]
name = "paste-impl"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
dependencies = [
"proc-macro-hack",
]
[[package]]
name = "ppc750cl"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"num-traits",
"ppc750cl-macros",
@ -69,7 +209,7 @@ dependencies = [
[[package]]
name = "ppc750cl-fuzz"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"num_cpus",
"ppc750cl",
@ -77,16 +217,24 @@ dependencies = [
[[package]]
name = "ppc750cl-macros"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ppc750cl-py"
version = "0.1.1"
dependencies = [
"ppc750cl",
"pyo3",
]
[[package]]
name = "ppc750cl-rand"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"ppc750cl",
"rand_core",
@ -99,6 +247,12 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.28"
@ -108,6 +262,55 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "pyo3"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af205762ba65eec9f27a2fa1a57a40644e8e3368784b8c8b2f2de48f6e8ddd96"
dependencies = [
"cfg-if",
"indoc",
"inventory",
"libc",
"parking_lot",
"paste",
"pyo3-build-config",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755944027ce803c7238e59c5a18e59c1d0a4553db50b23e9ba209a568353028d"
dependencies = [
"once_cell",
]
[[package]]
name = "pyo3-macros"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd31b36bccfd902c78804bd96c28ea93eac6fa0ca311f9d21ef2230b6665b29a"
dependencies = [
"pyo3-macros-backend",
"quote",
"syn",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c21c59ba36db9c823e931c662766b0dd01a030b1d96585b67d8857a96a56b972"
dependencies = [
"proc-macro2",
"pyo3-build-config",
"quote",
"syn",
]
[[package]]
name = "quote"
version = "1.0.9"
@ -158,6 +361,21 @@ dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sfmt"
version = "0.6.0"
@ -168,6 +386,12 @@ dependencies = [
"rand_core",
]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "syn"
version = "1.0.74"
@ -185,8 +409,36 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unindent"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -1,6 +1,7 @@
[workspace]
members = [
"disasm",
"disasm-py",
"macros",
"fuzz",
"rand",

16
disasm-py/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "ppc750cl-py"
version = "0.1.1"
edition = "2018"
authors = ["Richard Patel <me@terorie.dev>"]
license = "GPL-3.0-or-later"
description = "Python bindings for PowerPC 750CL Disassembler"
repository = "https://github.com/terorie/ppc750cl"
[lib]
name = "ppc750cl"
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.14", features = ["extension-module", "multiple-pymethods"] }
ppc750cl = { version = "0.1.1", path = "../disasm" }

137
disasm-py/src/lib.rs Normal file
View File

@ -0,0 +1,137 @@
use pyo3::prelude::*;
use pyo3::{PyIterProtocol, PyObjectProtocol};
#[pyclass]
struct Ins(ppc750cl::Ins);
macro_rules! ins_ufield {
($name:ident) => {
#[pymethods]
impl Ins {
#[getter]
fn $name(&self) -> PyResult<u32> {
Ok(self.0.$name() as u32)
}
}
};
}
macro_rules! ins_ifield {
($name:ident) => {
#[pymethods]
impl Ins {
#[getter]
fn $name(&self) -> PyResult<i32> {
Ok(self.0.$name() as i32)
}
}
};
}
#[pymethods]
impl Ins {
#[new]
fn new(code: u32, addr: u32) -> Self {
Ins(ppc750cl::Ins::new(code, addr))
}
#[getter]
fn code(&self) -> PyResult<u32> {
Ok(self.0.code)
}
#[getter]
fn addr(&self) -> PyResult<u32> {
Ok(self.0.addr)
}
}
ins_ufield!(rc);
ins_ufield!(aa);
ins_ufield!(lk);
ins_ufield!(l);
ins_ufield!(oe);
ins_ufield!(w);
ins_ufield!(s);
ins_ufield!(d);
ins_ufield!(a);
ins_ufield!(b);
ins_ufield!(c);
ins_ufield!(crb_d);
ins_ufield!(crb_a);
ins_ufield!(crb_b);
ins_ufield!(crm);
ins_ufield!(sr);
ins_ufield!(spr);
ins_ufield!(fm);
ins_ufield!(crf_d);
ins_ufield!(crf_s);
ins_ifield!(simm);
ins_ufield!(uimm);
ins_ufield!(bo);
ins_ufield!(bi);
ins_ufield!(sh);
ins_ufield!(mb);
ins_ufield!(me);
ins_ufield!(me_31sub);
ins_ifield!(bd);
ins_ifield!(li);
ins_ufield!(to);
ins_ufield!(ps_l);
ins_ifield!(ps_d);
impl From<ppc750cl::Ins> for Ins {
fn from(ins: ppc750cl::Ins) -> Self {
Self(ins)
}
}
#[pyproto]
impl<'a> PyObjectProtocol<'a> for Ins {
fn __str__(&self) -> String {
self.0.to_string()
}
}
#[pyclass]
struct DisasmIterator {
bytes: Vec<u8>,
addr: u32,
offset: u32,
}
#[pyproto]
impl PyIterProtocol for DisasmIterator {
fn __iter__(slf: PyRef<Self>) -> PyRef<DisasmIterator> {
slf
}
fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<Ins>> {
if (slf.bytes.len() as u32) - slf.offset < 4 {
return Ok(None);
}
let code = ((slf.bytes[(slf.offset + 0) as usize] as u32) << 24)
| ((slf.bytes[(slf.offset + 1) as usize] as u32) << 16)
| ((slf.bytes[(slf.offset + 2) as usize] as u32) << 8)
| (slf.bytes[(slf.offset + 3) as usize] as u32);
slf.offset += 4;
let ins = Ins::new(code, slf.addr);
slf.addr += 4;
Ok(Some(ins))
}
}
#[pyfunction]
fn disasm_iter<'a>(code: &[u8], addr: u32) -> PyResult<DisasmIterator> {
Ok(DisasmIterator {
bytes: code.to_vec(),
addr,
offset: 0,
})
}
#[pymodule]
fn ppc750cl(_: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Ins>()?;
m.add_wrapped(wrap_pyfunction!(disasm_iter))?;
Ok(())
}

View File

@ -1,6 +1,6 @@
[package]
name = "ppc750cl"
version = "0.1.0"
version = "0.1.1"
edition = "2018"
authors = ["Richard Patel <me@terorie.dev>"]
license = "GPL-3.0-or-later"
@ -10,4 +10,4 @@ repository = "https://github.com/terorie/ppc750cl"
[dependencies]
num-traits = "0.2.14"
ppc750cl-macros = { path = "../macros", version = "0.1.0" }
ppc750cl-macros = { path = "../macros", version = "0.1.1" }

34
disasm/src/iter.rs Normal file
View File

@ -0,0 +1,34 @@
use crate::Ins;
/// Returns an iterator of instructions in the given byte slice.
pub fn disasm_iter(code: &[u8], addr: u32) -> DisasmIterator {
DisasmIterator { code, addr }
}
pub struct DisasmIterator<'a> {
code: &'a [u8],
addr: u32,
}
impl<'a> Iterator for DisasmIterator<'a> {
type Item = Ins;
fn next(&mut self) -> Option<Self::Item> {
if self.code.len() < 4 {
return None;
}
let code = ((self.code[0] as u32) << 24)
| ((self.code[1] as u32) << 16)
| ((self.code[2] as u32) << 8)
| (self.code[3] as u32);
self.code = &self.code[4..];
let addr = self.addr;
self.addr += 4;
Some(Ins::new(code, addr))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let count = self.code.len() / 4;
(count, Some(count))
}
}

View File

@ -11,10 +11,12 @@ use ppc750cl_macros::write_asm;
mod macros;
pub mod formatter;
mod isa;
mod iter;
pub use crate::formatter::AsmFormatter;
use crate::formatter::SimpleFormatter;
pub use crate::isa::Opcode;
pub use crate::iter::{disasm_iter, DisasmIterator};
#[derive(Default, Clone)]
pub struct Ins {
@ -40,7 +42,8 @@ where
macro_rules! ins_bit {
($func:ident, $idx:expr) => {
fn $func(&self) -> u8 {
#[inline(always)]
pub fn $func(&self) -> u8 {
bit(self.code, $idx)
}
};
@ -48,7 +51,8 @@ macro_rules! ins_bit {
macro_rules! ins_ufield {
($func:ident, $return_type:ident, $range:expr) => {
fn $func(&self) -> $return_type {
#[inline(always)]
pub fn $func(&self) -> $return_type {
debug_assert!(
($range).len() / 8 <= (std::mem::size_of::<$return_type>()),
"{:?} does not fit in {}",
@ -62,7 +66,8 @@ macro_rules! ins_ufield {
macro_rules! ins_ifield {
($func:ident, $range:expr) => {
fn $func(&self) -> i32 {
#[inline(always)]
pub fn $func(&self) -> i32 {
debug_assert!(
($range).len() / 8 <= (std::mem::size_of::<i32>()),
"{:?} does not fit in {}",
@ -78,7 +83,8 @@ macro_rules! ins_ifield {
}
};
($func:ident, $range:expr, $shift:literal) => {
fn $func(&self) -> i32 {
#[inline(always)]
pub fn $func(&self) -> i32 {
debug_assert!(
($range).len() / 8 <= (std::mem::size_of::<i32>()),
"{:?} does not fit in {}",
@ -123,7 +129,7 @@ impl Ins {
ins_ufield!(crm, u8, 12..20);
ins_ufield!(sr, u8, 12..16);
fn spr(&self) -> u16 {
pub fn spr(&self) -> u16 {
bits::<u16>(self.code, 11..16) | (bits::<u16>(self.code, 16..21) << 5)
}
ins_ufield!(fm, u16, 7..15);
@ -136,7 +142,7 @@ impl Ins {
ins_ufield!(sh, u8, 16..21);
ins_ufield!(mb, u8, 21..26);
ins_ufield!(me, u8, 26..31);
fn me_31sub(&self) -> u8 {
pub fn me_31sub(&self) -> u8 {
31 - self.me()
}
ins_ifield!(bd, 16..30, 2);
@ -161,7 +167,7 @@ impl Ins {
// Ported from
// https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/Common/GekkoDisassembler.cpp
#[inline]
#[inline(always)]
fn write_asm_branch<F, W>(&self, out: &mut F, bname: &str) -> std::io::Result<()>
where
F: AsmFormatter<W>,

View File

@ -1,6 +1,6 @@
[package]
name = "ppc750cl-fuzz"
version = "0.1.0"
version = "0.1.1"
edition = "2018"
authors = ["Richard Patel <me@terorie.dev>"]
license = "GPL-3.0-or-later"
@ -9,4 +9,4 @@ repository = "https://github.com/terorie/ppc750cl"
[dependencies]
num_cpus = "1.13"
ppc750cl = { path = "../disasm", version = "0.1.0" }
ppc750cl = { path = "../disasm", version = "0.1.1" }

View File

@ -1,6 +1,6 @@
[package]
name = "ppc750cl-macros"
version = "0.1.0"
version = "0.1.1"
edition = "2018"
authors = ["Richard Patel <me@terorie.dev>"]
license = "GPL-3.0-or-later"

View File

@ -1,6 +1,6 @@
[package]
name = "ppc750cl-rand"
version = "0.1.0"
version = "0.1.1"
edition = "2018"
authors = ["Richard Patel <me@terorie.dev>"]
license = "GPL-3.0-or-later"
@ -8,6 +8,6 @@ description = "Generate random PowerPC 750CL instructions"
repository = "https://github.com/terorie/ppc750cl"
[dependencies]
ppc750cl = { path = "../disasm", version = "0.1.0" }
ppc750cl = { path = "../disasm", version = "0.1.1" }
rand_core = "0.5"
sfmt = "0.6"