1
Fork 0

Compare commits

..

No commits in common. "c27e748f436bb9cbd9c0f6749e8a4c5aa4635b1e" and "b9e56b5add98f2c06e20058364941c5af304fdb8" have entirely different histories.

9 changed files with 40 additions and 282 deletions

View file

@ -1,121 +0,0 @@
name: CI
on:
push:
branches:
- main
tags:
- '*'
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
linux:
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64, x86, aarch64]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
windows:
runs-on: windows-latest
strategy:
matrix:
target: [x64, x86]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
architecture: ${{ matrix.target }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
macos:
runs-on: macos-latest
strategy:
matrix:
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
- name: Test
run: |
python3 -m venv ${PWD}/.venv
. .venv/bin/activate
maturin --version
maturin develop
python3 test.py
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- name: Upload sdist
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
release:
name: Release
runs-on: ubuntu-latest
if: "startsWith(github.ref, 'refs/tags/')"
needs: [linux, windows, macos, sdist]
steps:
- uses: actions/download-artifact@v3
with:
name: wheels
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --non-interactive --skip-existing *

16
Cargo.lock generated
View file

@ -31,6 +31,14 @@ dependencies = [
"scroll",
]
[[package]]
name = "goblin-pyo3"
version = "0.0.2"
dependencies = [
"goblin",
"pyo3",
]
[[package]]
name = "heck"
version = "0.4.1"
@ -74,14 +82,6 @@ dependencies = [
"autocfg",
]
[[package]]
name = "oelf"
version = "0.0.4"
dependencies = [
"goblin",
"pyo3",
]
[[package]]
name = "once_cell"
version = "1.19.0"

View file

@ -1,6 +1,6 @@
[package]
name = "oelf"
version = "0.0.4"
name = "goblin-pyo3"
version = "0.0.2"
edition = "2021"
[lib]

View file

@ -10,4 +10,4 @@ classifiers = [
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
dynamic = ["version"]

View file

@ -3,23 +3,19 @@ use std::{
io::Read,
};
use goblin::mach::{Mach, SingleArch};
use goblin::mach::Mach;
use pyo3::{exceptions::PyTypeError, prelude::*};
mod exports;
mod header;
mod imports;
mod load_commands;
mod sections;
mod segments;
mod symbols;
use exports::Export;
use header::Header;
use imports::Import;
use load_commands::LoadCommand;
use sections::{Section, Sections};
use segments::Segment;
use symbols::Symbols;
#[pyclass]
@ -61,24 +57,6 @@ impl Object {
let macho = match object {
goblin::Object::Mach(Mach::Binary(macho)) => macho,
goblin::Object::Mach(Mach::Fat(march)) => {
let mut macho = None;
for arch in &march {
let arch = arch.map_err(|_| {
PyErr::new::<PyTypeError, _>("cannot parse single arch from Mach-O file")
})?;
if let SingleArch::MachO(m) = arch {
macho = Some(m);
break;
}
}
match macho {
Some(macho) => macho,
None => return Err(PyErr::new::<PyTypeError, _>("not a macho file")),
}
}
_ => return Err(PyErr::new::<PyTypeError, _>("not a macho file")),
};
@ -104,23 +82,13 @@ impl Object {
Symbols::from(self.macho().symbols())
}
fn segments(&self) -> Vec<Segment> {
self.macho()
.segments
.into_iter()
.map(|seg| seg.into())
.collect()
}
fn sections(&self) -> Sections {
let macho = self.macho();
let mut sections = vec![];
let mut idx = 0;
for sect_iter in macho.segments.sections() {
sections.extend(sect_iter.map(|section| {
idx += 1;
let (sect, _data) = section.unwrap();
Section::from((idx, sect))
Section::from(sect)
}));
}
Sections { sections }
@ -151,14 +119,6 @@ impl Object {
.map_err(|_| PyErr::new::<PyTypeError, _>("failed"))?;
Ok(imports.into_iter().map(|exp| exp.into()).collect())
}
fn load_commands(&self) -> Vec<LoadCommand> {
self.macho()
.load_commands
.iter()
.map(|cmd| cmd.into())
.collect()
}
}
impl Drop for Object {

View file

@ -1,26 +0,0 @@
use pyo3::prelude::*;
#[derive(Debug, Clone)]
#[pyclass]
pub struct LoadCommand {
#[pyo3(get)]
offset: usize,
#[pyo3(get)]
command: String,
}
#[pymethods]
impl LoadCommand {
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
impl From<&goblin::mach::load_command::LoadCommand> for LoadCommand {
fn from(lcmd: &goblin::mach::load_command::LoadCommand) -> Self {
LoadCommand {
offset: lcmd.offset,
command: format!("{:?}", lcmd.command),
}
}
}

View file

@ -3,8 +3,6 @@ use pyo3::prelude::*;
#[derive(Debug, Clone)]
#[pyclass]
pub struct Section {
#[pyo3(get)]
index: usize,
#[pyo3(get)]
name: Option<String>,
#[pyo3(get)]
@ -32,10 +30,9 @@ impl Section {
}
}
impl From<(usize, goblin::mach::segment::Section)> for Section {
fn from((index, section): (usize, goblin::mach::segment::Section)) -> Self {
impl From<goblin::mach::segment::Section> for Section {
fn from(section: goblin::mach::segment::Section) -> Self {
Section {
index,
name: section.name().ok().map(|s| s.to_string()),
segment: section.segname().ok().map(|s| s.to_string()),
addr: section.addr,

View file

@ -1,54 +0,0 @@
use pyo3::prelude::*;
#[derive(Debug, Clone)]
#[pyclass]
pub struct Segment {
#[pyo3(get)]
cmd: u32,
#[pyo3(get)]
cmdsize: u32,
#[pyo3(get)]
name: Option<String>,
#[pyo3(get)]
vmaddr: u64,
#[pyo3(get)]
vmsize: u64,
#[pyo3(get)]
fileoff: u64,
#[pyo3(get)]
filesize: u64,
#[pyo3(get)]
maxprot: u32,
#[pyo3(get)]
initprot: u32,
#[pyo3(get)]
nsects: u32,
#[pyo3(get)]
flags: u32,
}
#[pymethods]
impl Segment {
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
impl From<&goblin::mach::segment::Segment<'_>> for Segment {
fn from(segm: &goblin::mach::segment::Segment) -> Self {
let segname = segm.name().ok().map(|s| s.to_string());
Segment {
cmd: segm.cmd,
cmdsize: segm.cmdsize,
name: segname,
vmaddr: segm.vmaddr,
vmsize: segm.vmsize,
fileoff: segm.fileoff,
filesize: segm.filesize,
maxprot: segm.maxprot,
initprot: segm.initprot,
nsects: segm.nsects,
flags: segm.flags,
}
}
}

48
test.py
View file

@ -1,17 +1,28 @@
import sys
import oelf
path = "target/debug/liboelf.dylib"
if len(sys.argv) > 1:
path = sys.argv[1]
g = oelf.Object(path)
print(f"{g.header=}")
print(f"{g.name=}")
g = oelf.Object("test.py")
g = oelf.Object("mylib.dylib")
print(g.header)
print(g.name)
print("symbols")
for symbol in g.symbols():
print(symbol)
globsym = None
start = -1
end = 9999999999
for sym in g.symbols():
if "META" in sym.name and sym.is_global:
if globsym is None:
globsym = sym
start = sym.meta.n_value
for sym in g.symbols():
if sym.meta.n_value > start and sym.meta.n_value < end:
print(f"sym after the found one: {sym}")
end = sym.meta.n_value
print(f"found symbol {globsym.name} from {start} to {end}, size: {end-start}")
print(globsym)
print("libs")
print(g.libs)
@ -20,21 +31,12 @@ print("rpaths")
print(g.rpaths)
print("exports")
for export in g.exports():
print(export)
print(len(g.exports()))
print("imports")
for imp in g.imports():
print(imp)
print("segments")
for segment in g.segments():
print(f"{segment}")
print(len(g.imports()))
print("sections")
for section in g.sections():
print(f"{section}")
print("load commands")
for lcmd in g.load_commands():
print(lcmd)
for idx, section in enumerate(g.sections()):
print(f"{idx+1}. {section}")