Metadata-Version: 2.4
Name: dwarffi
Version: 0.0.2
Summary: Basic Python project scaffold for dwarffi.
Requires-Python: >=3.10
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Description-Content-Type: text/markdown

# dwarffi
An authentic, DWARF-powered FFI for Python.

dwarffi allows you to interact with C memory layouts using Intermediate Symbol Files (ISF) generated from DWARF debug information. It provides a CFFI-like experience without requiring header files—instead, it uses the actual compiled structures from your binaries.

Whether you're doing embedded systems reverse engineering, interacting with a QEMU instance, or analyzing kernel memory, dwarffi ensures that bitness, endianness, and padding are handled exactly as they appear in the target architecture.

## 🚀 Features
DWARF-Native: No need to rewrite C headers. Just point to a .json or .json.xz ISF file (generated by dwarf2json).

Architecture Agnostic: Seamlessly handles Big Endian (PowerPC/MIPS) and Little Endian (ARM/x86) in the same script.

Dynamic cdef: Compile C code on the fly to generate types, with automatic "type-keep" logic to prevent the compiler from stripping unused definitions.

Recursive Typedefs: Automatic type decay for typedef chains.

C-Style Magic: Supports pointer arithmetic (ptr + 5), array slicing (arr[1:5]), and deep struct initialization via nested Python dictionaries.

Safety: Automatic bit-masking and sign-extension to mimic C integer overflow/underflow behavior in Python.

## 📦 Installation
```bash
pip install dwarffi
```
Note: For the cdef functionality, you will need a C compiler (like gcc or clang) and dwarf2json installed in your PATH.

## 🛠️ Quick Start
### 1. The CFFI-style cdef
If you have a snippet of C and want to work with it immediately:

Python
from dwarffi.dffi import DFFI

ffi = DFFI()
ffi.cdef("""
    struct sensor_data {
        uint32_t timestamp;
        int16_t  readings[3];
        uint8_t  status;
    };
""")

# Create an instance in a fresh bytearray
```python
sensor = ffi.new("struct sensor_data", {
    "timestamp": 1234567,
    "readings": [10, -5, 20],
    "status": 0x01
})

print(f"Bytes: {sensor.to_bytes().hex()}")
print(f"Reading[1]: {sensor.readings[1]}") # -5
```
2. Embedded Architecture Analysis
Analyze a Big Endian MIPS structure from a raw binary dump:

Python
```python
# Load a pre-generated ISF for a MIPS target
ffi = DFFI("mips_be_target.json")
```

# Map existing memory (e.g., from an emulator or hex dump)
```python
raw_data = bytearray(b'\x00\x00\x12\x34\xff\xff\xff\xfb')
cpu_ctx = ffi.from_buffer("struct cpu_context", raw_data)
```

# Values are automatically unpacked according to MIPS Big Endian rules
```python
print(hex(cpu_ctx.pc))      # 0x1234
print(cpu_ctx.status)       # -5 (Sign-extended from 32-bit BE)
```
# 🧩 Advanced Usage
## Anonymous Unions and Bitfields

dwarffi lets you access anonymous members directly, common in hardware register maps.

```python
ffi.cdef("""
struct reg_map {
    union {
        uint32_t ALL;
        struct {
            uint16_t LOW;
            uint16_t HIGH;
        };
    };
};
""")

reg = ffi.new("struct reg_map")
reg.ALL = 0x12345678
print(hex(reg.HIGH)) # 0x1234
```
## Pointer Arithmetic
```python
ptr = ffi.cast("int *", 0x4000)
next_ptr = ptr + 1  # Increments by sizeof(int)
print(hex(next_ptr.address)) # 0x4004
```

## ⚙️ How it Works

`dwarffi` acts as a middleman between raw memory and Python objects.

- Parsing: It reads ISF files (which represent the DWARF tree).
- Synthesis: It creates Pythonic wrappers for C types.
- Memory Mapping: Using struct.pack and struct.unpack, it translates Python integers/strings into the exact byte representation required by the target architecture.

## 🤝 Contributing
We welcome contributions! Please ensure that you add tests for any new features. dwarffi uses pytest for its extensive test suite, covering integer packing, architecture variances, and magic method semantics.

```bash
pytest tests/
```
