Metadata-Version: 2.4
Name: objectfile
Version: 0.0.1a1
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Rust
Classifier: Topic :: Software Development :: Disassemblers
Classifier: Topic :: System :: Software Distribution
Classifier: Typing :: Typed
Requires-Dist: pycxxfilt>=1.2 ; extra == 'cli'
Provides-Extra: cli
License-File: LICENSE-APACHE
License-File: LICENSE-MIT
Summary: Parse ELF, Mach-O, PE, and WebAssembly object files: metadata, symbols, and dependencies
Keywords: object,elf,pe,mach-o,symbols,binary,executable
Author-email: Christian Heimes <christian@python.org>
License-Expression: Apache-2.0 OR MIT
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Project-URL: Changelog, https://github.com/tiran/objectfile/releases
Project-URL: Homepage, https://github.com/tiran/objectfile
Project-URL: Issues, https://github.com/tiran/objectfile/issues
Project-URL: Repository, https://github.com/tiran/objectfile

# objectfile

Parse ELF, Mach-O, PE, and WebAssembly binaries (plus COFF and XCOFF) from Python:
read their format metadata, imported and exported symbols, shared-library dependencies,
and symbol tables. `objectfile` is a fast, typed extension built with
[PyO3](https://pyo3.rs) on top of the read API of the Rust
[`object`](https://crates.io/crates/object) crate.

Files are **memory-mapped**, not read into memory, so even very large binaries only
page in what you actually touch.

## Install

```console
$ pip install objectfile
```

Wheels are built with the stable ABI (`abi3`), so a single wheel per platform supports
CPython 3.12 and newer.

## Quickstart

```python
import objectfile

obj = objectfile.parse_file("/bin/ls")

# Metadata
obj.format  # Format.Elf
obj.architecture  # Architecture.X86_64
obj.is_64  # True
obj.endianness  # Endianness.Little
obj.kind  # ObjectKind.Dynamic

# Shared-library dependencies (DT_NEEDED / dylibs / imported DLLs)
list(obj.libraries())  # ['libc.so.6', ...]

# Imported and exported symbols (dynamic-linking view)
for imp in obj.imports():
    print(imp.name, imp.library, imp.is_weak)
for exp in obj.exports():
    print(exp.name, hex(exp.address) if exp.address is not None else None)

# Symbol tables (symbol-table view)
undefined = [s for s in obj.symbols() if s.is_undefined]
for sym in obj.dynamic_symbols():
    print(sym.name, sym.kind, sym.scope)
```

All collections (`imports()`, `exports()`, `libraries()`, `symbols()`,
`dynamic_symbols()`) are methods returning lazy iterators - pass them to `list()`,
`sorted()`, or a comprehension.

You can also parse an in-memory buffer:

```python
obj = objectfile.parse(open("/bin/ls", "rb").read())
```

## Demangling symbols

Symbol names are returned raw (mangled), e.g. `_ZN3std2io5Write9write_fmt`. To turn
them into readable signatures, pair `objectfile` with
[pycxxfilt](https://pypi.org/project/pycxxfilt/), which demangles C++ and Rust symbols
(including the IA-64/Itanium and MSVC schemes):

```python
import objectfile
import pycxxfilt

obj = objectfile.parse_file("/bin/ls")
for sym in obj.dynamic_symbols():
    if sym.name:
        print(pycxxfilt.demangle(sym.name))
```

## Command line (unstable)

A small `objectfile` command prints a summary of a file:

```console
$ objectfile /bin/ls
format:       Elf
architecture: X86_64
bits:         64
endianness:   Little
kind:         Dynamic
libraries (1):
  libc.so.6
imports:      128
exports:      0
```

Add `--imports`, `--exports`, or `--symbols` to list those entries, or run it as
`python -m objectfile <path>`. With the `cli` extra installed
(`pip install objectfile[cli]`, which pulls in
[pycxxfilt](https://pypi.org/project/pycxxfilt/)), `--demangle` renders C++/Rust symbol
names in a readable form.

> **The CLI and its output format are unstable** and may change at any time. Do not
> parse this output in scripts - use the Python API instead.

## API

- `parse(data: bytes) -> ObjectFile` - parse a buffer.
- `parse_file(path) -> ObjectFile` - memory-map a file (`str` or `os.PathLike`) and
  parse it.
- `parse` accepts any buffer-protocol object (`bytes`, `bytearray`, `memoryview`,
  `mmap`, ...).
- `ObjectFile` - properties `format`, `architecture`, `is_64`, `endianness`, `kind`;
  methods `imports()`, `exports()`, `libraries()`, `symbols()`, `dynamic_symbols()`,
  each returning a lazy iterator.
- `Import` - `name`, `ordinal`, `library`, `is_weak`.
- `Export` - `name`, `ordinal`, `address`, `is_weak`, `version`, `version_hidden`.
- `Symbol` - `name`, `address`, `size`, `kind`, `scope`, `is_undefined`, `is_global`,
  `is_weak`, `section_index`, `version`, `version_hidden`.
- `Import`, `Export`, and `Symbol` are comparable, hashable, and ordered by name, so
  `sorted(...)` works; they are also directly constructible.
- Enums: `Format`, `Architecture`, `Endianness`, `ObjectKind`, `SymbolKind`,
  `SymbolScope`.

`imports()`/`exports()` are the dynamic-linking tables (what the loader resolves);
`symbols()`/`dynamic_symbols()` are the symbol tables (every symbol) - complementary
views. Invalid input raises `ObjectFileError` (a subclass of `ValueError`); a missing
file raises the usual `OSError` (e.g. `FileNotFoundError`).

### Symbol versions (ELF)

Exports and dynamic symbols carry the GNU symbol version: `.version` (e.g.
`GLIBCXX_3.4.22`) and `.version_hidden` (`False` for a default version - `nm`'s `@@` -
and `True` for a non-default one - `@`). It is set on `exports()` and
`dynamic_symbols()`; the full `symbols()` table (`.symtab`) is unversioned. This is
ELF-specific; Mach-O, PE, and wasm have no equivalent per-symbol versioning, so
`version` is `None` there. ELF version-node marker symbols (the pseudo-symbols named
after a version node) are filtered out of `exports()`, but remain in
`dynamic_symbols()`, which is the raw symbol-table view.

Enum members stringify to their bare name for display/serialization: `str(obj.format)`
is `"Elf"` (while `repr` keeps `Format.Elf`).

## License

Dual-licensed under either of [Apache-2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT) at
your option - the same terms as the upstream `object` crate.

