diff --git a/crates/goblin-pyo3/src/exports.rs b/crates/goblin-pyo3/src/exports.rs new file mode 100644 index 0000000..eecf388 --- /dev/null +++ b/crates/goblin-pyo3/src/exports.rs @@ -0,0 +1,91 @@ +use pyo3::prelude::*; + +#[derive(Debug, Default, Clone)] +#[pyclass] +enum ExportTyp { + #[default] + Regular, + Reexport, + Stub +} + +#[derive(Debug, Default, Clone)] +#[pyclass] +struct ExportInfo { + #[pyo3(get)] + typ: ExportTyp, + #[pyo3(get)] + address: u64, + #[pyo3(get)] + flags: u64, + #[pyo3(get)] + lib: String, + #[pyo3(get)] + lib_symbol_name: Option, +} + +impl From> for ExportInfo { + fn from(info: goblin::mach::exports::ExportInfo) -> Self { + use goblin::mach::exports::ExportInfo::*; + match info { + Regular { address, flags } => { + Self { + typ: ExportTyp::Regular, + address, + flags, + .. Default::default() + } + } + Reexport { lib, lib_symbol_name, flags } => { + Self { + typ: ExportTyp::Reexport, + lib: lib.to_string(), + lib_symbol_name: lib_symbol_name.map(|s| s.to_string()), + flags, + .. Default::default() + } + } + Stub { + flags, .. + } => { + Self { + typ: ExportTyp::Stub, + flags, + .. Default::default() + } + } + } + } +} + +#[derive(Debug)] +#[pyclass] +pub struct Export { + #[pyo3(get)] + name: String, + #[pyo3(get)] + info: ExportInfo, + #[pyo3(get)] + size: usize, + #[pyo3(get)] + offset: u64, +} + +#[pymethods] +impl Export { + fn __repr__(&self) -> String { + format!("{:?}", self) + } +} + +impl From> for Export { + fn from(export: goblin::mach::exports::Export) -> Self { + Self { + name: export.name, + info: export.info.into(), + size: export.size, + offset: export.offset, + } + } +} + diff --git a/crates/goblin-pyo3/src/header.rs b/crates/goblin-pyo3/src/header.rs new file mode 100644 index 0000000..f412e31 --- /dev/null +++ b/crates/goblin-pyo3/src/header.rs @@ -0,0 +1,44 @@ +use pyo3::prelude::*; + +#[derive(Debug, Clone)] +#[pyclass] +pub struct Header { + #[pyo3(get)] + magic: u32, + #[pyo3(get)] + cputype: u32, + #[pyo3(get)] + cpusubtype: u32, + #[pyo3(get)] + filetype: u32, + #[pyo3(get)] + ncmds: usize, + #[pyo3(get)] + sizeofcmds: u32, + #[pyo3(get)] + flags: u32, + #[pyo3(get)] + reserved: u32, +} + +impl From for Header { + fn from(other: goblin::mach::header::Header) -> Self { + Header { + magic: other.magic, + cputype: other.cputype, + cpusubtype: other.cpusubtype, + filetype: other.filetype, + ncmds: other.ncmds, + sizeofcmds: other.sizeofcmds, + flags: other.flags, + reserved: other.reserved, + } + } +} + +#[pymethods] +impl Header { + fn __repr__(&self) -> String { + format!("{:?}", self) + } +} diff --git a/crates/goblin-pyo3/src/imports.rs b/crates/goblin-pyo3/src/imports.rs new file mode 100644 index 0000000..ab36376 --- /dev/null +++ b/crates/goblin-pyo3/src/imports.rs @@ -0,0 +1,47 @@ +use pyo3::prelude::*; + +#[derive(Debug)] +#[pyclass] +pub struct Import { + #[pyo3(get)] + name: String, + #[pyo3(get)] + dylib: String, + #[pyo3(get)] + is_lazy: bool, + #[pyo3(get)] + offset: u64, + #[pyo3(get)] + size: usize, + #[pyo3(get)] + address: u64, + #[pyo3(get)] + addend: i64, + #[pyo3(get)] + is_weak: bool, + #[pyo3(get)] + start_of_sequence_offset: u64, +} + +#[pymethods] +impl Import { + fn __repr__(&self) -> String { + format!("{:?}", self) + } +} + +impl From> for Import { + fn from(import: goblin::mach::imports::Import<'_>) -> Self { + Self { + name: import.name.to_string(), + dylib: import.dylib.to_string(), + is_lazy: import.is_lazy, + offset: import.offset, + size: import.size, + address: import.address, + addend: import.addend, + is_weak: import.is_weak, + start_of_sequence_offset: import.start_of_sequence_offset, + } + } +} diff --git a/crates/goblin-pyo3/src/lib.rs b/crates/goblin-pyo3/src/lib.rs index 4ad0289..3eb1f35 100644 --- a/crates/goblin-pyo3/src/lib.rs +++ b/crates/goblin-pyo3/src/lib.rs @@ -3,11 +3,19 @@ use std::{ io::Read, }; -use goblin::{ - mach::{symbols::Nlist, Mach}, -}; +use goblin::mach::Mach; use pyo3::{prelude::*, exceptions::PyTypeError}; +mod exports; +mod header; +mod imports; +mod symbols; + +use exports::Export; +use header::Header; +use imports::Import; +use symbols::Symbols; + #[pyclass] struct Object { len: usize, @@ -118,280 +126,6 @@ impl Drop for Object { } } } - -#[derive(Debug, Clone)] -#[pyclass] -struct Header { - #[pyo3(get)] - magic: u32, - #[pyo3(get)] - cputype: u32, - #[pyo3(get)] - cpusubtype: u32, - #[pyo3(get)] - filetype: u32, - #[pyo3(get)] - ncmds: usize, - #[pyo3(get)] - sizeofcmds: u32, - #[pyo3(get)] - flags: u32, - #[pyo3(get)] - reserved: u32, -} - -impl From for Header { - fn from(other: goblin::mach::header::Header) -> Self { - Header { - magic: other.magic, - cputype: other.cputype, - cpusubtype: other.cpusubtype, - filetype: other.filetype, - ncmds: other.ncmds, - sizeofcmds: other.sizeofcmds, - flags: other.flags, - reserved: other.reserved, - } - } -} - -#[pymethods] -impl Header { - fn __repr__(&self) -> String { - format!("{:?}", self) - } -} - -#[derive(Debug, Clone)] -#[pyclass] -struct Symbol { - #[pyo3(get)] - name: String, - - meta: Nlist, -} - -#[pymethods] -impl Symbol { - #[getter] - fn typ(&self) -> &'static str { - self.meta.type_str() - } - - #[getter] - fn global(&self) -> bool { - self.meta.is_global() - } - - #[getter] - fn weak(&self) -> bool { - self.meta.is_weak() - } - - #[getter] - fn undefined(&self) -> bool { - self.meta.is_undefined() - } - - #[getter] - fn stab(&self) -> bool { - self.meta.is_stab() - } - - fn __repr__(&self) -> String { - format!( - "Symbol {{ name: {}, global: {}, weak: {}, undefined: {}, stab: {} }}", - self.name, - self.global(), - self.weak(), - self.undefined(), - self.stab() - ) - } -} - -#[pyclass] -struct Symbols { - symbols: Vec, -} - -#[pymethods] -impl Symbols { - fn __iter__(slf: PyRef<'_, Self>) -> PyResult> { - let iter = SymbolIter { - inner: slf.symbols.clone().into_iter(), - }; - Py::new(slf.py(), iter) - } -} - -impl From> for Symbols { - fn from(other: goblin::mach::symbols::SymbolIterator) -> Self { - let symbols = other - .map(|sym| { - let (symname, meta) = sym.unwrap(); - Symbol { - name: symname.to_string(), - meta, - } - }) - .collect(); - - Symbols { symbols } - } -} - -#[pyclass] -struct SymbolIter { - inner: std::vec::IntoIter, -} - -#[pymethods] -impl SymbolIter { - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { - slf - } - - fn __next__(mut slf: PyRefMut<'_, Self>) -> Option { - slf.inner.next() - } -} - -#[derive(Debug, Default, Clone)] -#[pyclass] -enum ExportTyp { - #[default] - Regular, - Reexport, - Stub -} - -#[derive(Debug, Default, Clone)] -#[pyclass] -pub struct ExportInfo { - #[pyo3(get)] - typ: ExportTyp, - #[pyo3(get)] - address: u64, - #[pyo3(get)] - flags: u64, - #[pyo3(get)] - lib: String, - #[pyo3(get)] - lib_symbol_name: Option, -} - -impl From> for ExportInfo { - fn from(info: goblin::mach::exports::ExportInfo) -> Self { - use goblin::mach::exports::ExportInfo::*; - match info { - Regular { address, flags } => { - Self { - typ: ExportTyp::Regular, - address, - flags, - .. Default::default() - } - } - Reexport { lib, lib_symbol_name, flags } => { - Self { - typ: ExportTyp::Reexport, - lib: lib.to_string(), - lib_symbol_name: lib_symbol_name.map(|s| s.to_string()), - flags, - .. Default::default() - } - } - Stub { - flags, .. - } => { - Self { - typ: ExportTyp::Stub, - flags, - .. Default::default() - } - } - } - } -} - -#[derive(Debug)] -#[pyclass] -struct Export { - #[pyo3(get)] - name: String, - #[pyo3(get)] - info: ExportInfo, - #[pyo3(get)] - size: usize, - #[pyo3(get)] - offset: u64, -} - -#[pymethods] -impl Export { - fn __repr__(&self) -> String { - format!("{:?}", self) - } -} - -impl From> for Export { - fn from(export: goblin::mach::exports::Export) -> Self { - Self { - name: export.name, - info: export.info.into(), - size: export.size, - offset: export.offset, - } - } -} - -#[derive(Debug)] -#[pyclass] -struct Import { - #[pyo3(get)] - name: String, - #[pyo3(get)] - dylib: String, - #[pyo3(get)] - is_lazy: bool, - #[pyo3(get)] - offset: u64, - #[pyo3(get)] - size: usize, - #[pyo3(get)] - address: u64, - #[pyo3(get)] - addend: i64, - #[pyo3(get)] - is_weak: bool, - #[pyo3(get)] - start_of_sequence_offset: u64, -} - -#[pymethods] -impl Import { - fn __repr__(&self) -> String { - format!("{:?}", self) - } -} - -impl From> for Import { - fn from(import: goblin::mach::imports::Import<'_>) -> Self { - Self { - name: import.name.to_string(), - dylib: import.dylib.to_string(), - is_lazy: import.is_lazy, - offset: import.offset, - size: import.size, - address: import.address, - addend: import.addend, - is_weak: import.is_weak, - start_of_sequence_offset: import.start_of_sequence_offset, - } - } -} - #[pymodule] #[pyo3(name = "goblin")] fn py_goblin(_py: Python<'_>, m: &PyModule) -> PyResult<()> { diff --git a/crates/goblin-pyo3/src/symbols.rs b/crates/goblin-pyo3/src/symbols.rs new file mode 100644 index 0000000..58acb09 --- /dev/null +++ b/crates/goblin-pyo3/src/symbols.rs @@ -0,0 +1,99 @@ +use goblin::mach::symbols::Nlist; +use pyo3::prelude::*; + +#[derive(Debug, Clone)] +#[pyclass] +struct Symbol { + #[pyo3(get)] + name: String, + + meta: Nlist, +} + +#[pymethods] +impl Symbol { + #[getter] + fn typ(&self) -> &'static str { + self.meta.type_str() + } + + #[getter] + fn global(&self) -> bool { + self.meta.is_global() + } + + #[getter] + fn weak(&self) -> bool { + self.meta.is_weak() + } + + #[getter] + fn undefined(&self) -> bool { + self.meta.is_undefined() + } + + #[getter] + fn stab(&self) -> bool { + self.meta.is_stab() + } + + fn __repr__(&self) -> String { + format!( + "Symbol {{ name: {}, global: {}, weak: {}, undefined: {}, stab: {} }}", + self.name, + self.global(), + self.weak(), + self.undefined(), + self.stab() + ) + } +} + +#[pyclass] +pub struct Symbols { + symbols: Vec, +} + +#[pymethods] +impl Symbols { + fn __iter__(slf: PyRef<'_, Self>) -> PyResult> { + let iter = SymbolIter { + inner: slf.symbols.clone().into_iter(), + }; + Py::new(slf.py(), iter) + } +} + +impl From> for Symbols { + fn from(other: goblin::mach::symbols::SymbolIterator) -> Self { + let symbols = other + .map(|sym| { + let (symname, meta) = sym.unwrap(); + Symbol { + name: symname.to_string(), + meta, + } + }) + .collect(); + + Symbols { symbols } + } +} + +#[pyclass] +struct SymbolIter { + inner: std::vec::IntoIter, +} + +#[pymethods] +impl SymbolIter { + fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + slf + } + + fn __next__(mut slf: PyRefMut<'_, Self>) -> Option { + slf.inner.next() + } +} + +