Compare commits
10 commits
b9e56b5add
...
c27e748f43
Author | SHA1 | Date | |
---|---|---|---|
Jan-Erik Rediger | c27e748f43 | ||
Jan-Erik Rediger | f76597cb7c | ||
Jan-Erik Rediger | 6dba4064f2 | ||
Jan-Erik Rediger | 53708c2bb4 | ||
Jan-Erik Rediger | 1297ce2668 | ||
Jan-Erik Rediger | ffec4b5769 | ||
Jan-Erik Rediger | c07018a3aa | ||
Jan-Erik Rediger | 992506e516 | ||
Jan-Erik Rediger | 25d945f084 | ||
Jan-Erik Rediger | e005020934 |
121
.github/workflows/CI.yml
vendored
Normal file
121
.github/workflows/CI.yml
vendored
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
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
16
Cargo.lock
generated
|
@ -31,14 +31,6 @@ dependencies = [
|
||||||
"scroll",
|
"scroll",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "goblin-pyo3"
|
|
||||||
version = "0.0.2"
|
|
||||||
dependencies = [
|
|
||||||
"goblin",
|
|
||||||
"pyo3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -82,6 +74,14 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oelf"
|
||||||
|
version = "0.0.4"
|
||||||
|
dependencies = [
|
||||||
|
"goblin",
|
||||||
|
"pyo3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "goblin-pyo3"
|
name = "oelf"
|
||||||
version = "0.0.2"
|
version = "0.0.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|
|
@ -10,4 +10,4 @@ classifiers = [
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
]
|
]
|
||||||
|
dynamic = ["version"]
|
||||||
|
|
44
src/lib.rs
44
src/lib.rs
|
@ -3,19 +3,23 @@ use std::{
|
||||||
io::Read,
|
io::Read,
|
||||||
};
|
};
|
||||||
|
|
||||||
use goblin::mach::Mach;
|
use goblin::mach::{Mach, SingleArch};
|
||||||
use pyo3::{exceptions::PyTypeError, prelude::*};
|
use pyo3::{exceptions::PyTypeError, prelude::*};
|
||||||
|
|
||||||
mod exports;
|
mod exports;
|
||||||
mod header;
|
mod header;
|
||||||
mod imports;
|
mod imports;
|
||||||
|
mod load_commands;
|
||||||
mod sections;
|
mod sections;
|
||||||
|
mod segments;
|
||||||
mod symbols;
|
mod symbols;
|
||||||
|
|
||||||
use exports::Export;
|
use exports::Export;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use imports::Import;
|
use imports::Import;
|
||||||
|
use load_commands::LoadCommand;
|
||||||
use sections::{Section, Sections};
|
use sections::{Section, Sections};
|
||||||
|
use segments::Segment;
|
||||||
use symbols::Symbols;
|
use symbols::Symbols;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
@ -57,6 +61,24 @@ impl Object {
|
||||||
|
|
||||||
let macho = match object {
|
let macho = match object {
|
||||||
goblin::Object::Mach(Mach::Binary(macho)) => macho,
|
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")),
|
_ => return Err(PyErr::new::<PyTypeError, _>("not a macho file")),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,13 +104,23 @@ impl Object {
|
||||||
Symbols::from(self.macho().symbols())
|
Symbols::from(self.macho().symbols())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn segments(&self) -> Vec<Segment> {
|
||||||
|
self.macho()
|
||||||
|
.segments
|
||||||
|
.into_iter()
|
||||||
|
.map(|seg| seg.into())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn sections(&self) -> Sections {
|
fn sections(&self) -> Sections {
|
||||||
let macho = self.macho();
|
let macho = self.macho();
|
||||||
let mut sections = vec![];
|
let mut sections = vec![];
|
||||||
|
let mut idx = 0;
|
||||||
for sect_iter in macho.segments.sections() {
|
for sect_iter in macho.segments.sections() {
|
||||||
sections.extend(sect_iter.map(|section| {
|
sections.extend(sect_iter.map(|section| {
|
||||||
|
idx += 1;
|
||||||
let (sect, _data) = section.unwrap();
|
let (sect, _data) = section.unwrap();
|
||||||
Section::from(sect)
|
Section::from((idx, sect))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Sections { sections }
|
Sections { sections }
|
||||||
|
@ -119,6 +151,14 @@ impl Object {
|
||||||
.map_err(|_| PyErr::new::<PyTypeError, _>("failed"))?;
|
.map_err(|_| PyErr::new::<PyTypeError, _>("failed"))?;
|
||||||
Ok(imports.into_iter().map(|exp| exp.into()).collect())
|
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 {
|
impl Drop for Object {
|
||||||
|
|
26
src/load_commands.rs
Normal file
26
src/load_commands.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ use pyo3::prelude::*;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
pub struct Section {
|
pub struct Section {
|
||||||
|
#[pyo3(get)]
|
||||||
|
index: usize,
|
||||||
#[pyo3(get)]
|
#[pyo3(get)]
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
#[pyo3(get)]
|
#[pyo3(get)]
|
||||||
|
@ -30,9 +32,10 @@ impl Section {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<goblin::mach::segment::Section> for Section {
|
impl From<(usize, goblin::mach::segment::Section)> for Section {
|
||||||
fn from(section: goblin::mach::segment::Section) -> Self {
|
fn from((index, section): (usize, goblin::mach::segment::Section)) -> Self {
|
||||||
Section {
|
Section {
|
||||||
|
index,
|
||||||
name: section.name().ok().map(|s| s.to_string()),
|
name: section.name().ok().map(|s| s.to_string()),
|
||||||
segment: section.segname().ok().map(|s| s.to_string()),
|
segment: section.segname().ok().map(|s| s.to_string()),
|
||||||
addr: section.addr,
|
addr: section.addr,
|
||||||
|
|
54
src/segments.rs
Normal file
54
src/segments.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
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
48
test.py
|
@ -1,28 +1,17 @@
|
||||||
|
import sys
|
||||||
import oelf
|
import oelf
|
||||||
|
|
||||||
g = oelf.Object("test.py")
|
path = "target/debug/liboelf.dylib"
|
||||||
g = oelf.Object("mylib.dylib")
|
if len(sys.argv) > 1:
|
||||||
print(g.header)
|
path = sys.argv[1]
|
||||||
print(g.name)
|
|
||||||
|
g = oelf.Object(path)
|
||||||
|
print(f"{g.header=}")
|
||||||
|
print(f"{g.name=}")
|
||||||
|
|
||||||
print("symbols")
|
print("symbols")
|
||||||
globsym = None
|
for symbol in g.symbols():
|
||||||
start = -1
|
print(symbol)
|
||||||
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("libs")
|
||||||
print(g.libs)
|
print(g.libs)
|
||||||
|
@ -31,12 +20,21 @@ print("rpaths")
|
||||||
print(g.rpaths)
|
print(g.rpaths)
|
||||||
|
|
||||||
print("exports")
|
print("exports")
|
||||||
print(len(g.exports()))
|
for export in g.exports():
|
||||||
|
print(export)
|
||||||
|
|
||||||
print("imports")
|
print("imports")
|
||||||
print(len(g.imports()))
|
for imp in g.imports():
|
||||||
|
print(imp)
|
||||||
|
|
||||||
|
print("segments")
|
||||||
|
for segment in g.segments():
|
||||||
|
print(f"{segment}")
|
||||||
|
|
||||||
print("sections")
|
print("sections")
|
||||||
|
for section in g.sections():
|
||||||
|
print(f"{section}")
|
||||||
|
|
||||||
for idx, section in enumerate(g.sections()):
|
print("load commands")
|
||||||
print(f"{idx+1}. {section}")
|
for lcmd in g.load_commands():
|
||||||
|
print(lcmd)
|
||||||
|
|
Loading…
Reference in a new issue