Skip to main content

Python bindings for the x86sim C++ library, a cycle-accurate x86-64 simulator based on PTLsim.

Project description

x86sim

x86sim is a cycle-accurate x86-64 simulator, originally developed by Alexis Engelke as a fork of PTLsim by Matt Yourst. This package provides Python bindings to the x86sim C++ library, allowing you to configure the virtual address space, set initial register values, and run simulations of ELF binaries directly from Python.

Installation

The extension is built from the in-tree C++ core via CMake (driven by scikit-build-core). From the repository root:

pip install .

A C++26-capable compiler and CMake >= 3.25 are required.

Features

  • Cycle-accurate simulation of x86-64 instructions.
  • ELF Binary Loading: Parse and load ELF binaries, including segments and debugging information.
  • Custom Memory Management: Map memory segments with specific permissions.
  • Register Access: Read and write CPU registers during simulation.
  • Exception Handling: Detailed exceptions for various fault conditions.
  • Python Binding: Interface directly with the simulator using Python.

Key Components

Machine Class

The main class used to interact with the simulator (x86sim.Machine, a thin wrapper over the compiled x86sim.bindings.Machine). It provides methods to:

  • Load ELF binaries into the simulator.
  • Run the simulation.
  • Access and modify CPU registers.
  • Handle exceptions and retrieve simulation statistics.

ELF Class

Represents an ELF binary and provides methods to:

  • Parse ELF files from bytes and extract segments.
  • Handle debugging information like line mappings.
  • Add trampolines to binaries for controlled execution flow.

Segment Class

Represents a memory segment with attributes:

  • vaddr: Virtual address.
  • prot: Memory protection (read, write, execute).
  • size: Size of the segment.
  • data: Optional data contained in the segment.
  • stack: Indicates if the segment is a stack.

iN Classes (i8, i16, i32, i64)

Represents N-bit integers with proper wrapping and arithmetic operations. Useful for working with register values and ensuring correct bit-width behavior.

Utility Functions

  • simcompile: Context manager to compile code into an ELF binary using appropriate flags.
  • asm_preamble: Generates assembly code preamble with an entry label.
  • asm_stop_sim: Generates assembly instruction to stop the simulator (int 0x80).

Usage

Compiling and Loading an ELF Binary

from x86sim.simcompile import simcompile
from x86sim.elf import ELF
from x86sim import Machine

# Write your assembly code
code = """
.global _start
.intel_syntax noprefix
.text
_start:
    mov rax, -1
    int 0x80
"""

# Compile the code into an ELF binary
with simcompile(code=code) as f:
    elf = ELF.from_file(f)

# Create a simulator instance and load the ELF binary
sim = Machine()
sim.load_elf(elf)

# Run the simulation
sim.run()

# Access register values
print(f"RAX: {sim.registers.rax:#x}")

Accessing Memory

# Map a memory segment
address = sim.memmap(start=0x1000, prot=Prot.RW, length=0x1000)

# Write to memory
address[0x0] = b'\x01\x02\x03\x04'

# Read from memory
data = address.read(size=4)
print(f"Data: {data.hex()}")

glibc syscalls and Stream I/O

Machine is a register/memory simulator by default: an int 0x80 stops it and every other syscall raises. Several opt-in features extend it, all off by default:

  • glibc=True enables the portable Linux glibc-startup syscalls: the malloc/free heap (brk and anonymous mmap/munmap/mremap) plus arch_prctl, set_tid_address, set_robust_list, rseq, prlimit64, uname, getpid/getuid/…, futex and the synthetic signal syscalls. With glibc=False those syscalls raise.
  • stdin/stdout/stderr route the guest's read(0, ...) / write(1, ...) / write(2, ...) to Python file-like objects (anything exposing .read(n) / .write(bytes), such as io.BytesIO). No host file descriptors are ever touched — Python fully controls the mapping. An fd left as None is unconfigured and a guest I/O on it raises.
  • readlink=callable resolves the guest's readlink/readlinkat calls via a Python readlink(path: str) -> str | None (e.g. for /proc/self/exe, which glibc reads at startup). Returning None yields -ENOENT; without a callback the syscall returns -ENOSYS. No real filesystem is touched.
  • core="seq" selects the sequential CPU model instead of the default out-of-order one (core="ooo"). Both cores execute unaligned memory accesses correctly and can run glibc; the sequential core is simpler and slower, the out-of-order core is the cycle-accurate default.

These features require the guest to use the 64-bit syscall instruction (the Linux syscall ABI: number in rax, arguments in rdi, rsi, rdx, ...). int 0x80 remains the guest-exit sentinel.

Capturing guest output

import io
from x86sim import Machine

out = io.BytesIO()
sim = Machine(stdout=out)
# ... load a guest that does write(1, msg, len) then exit_group(0) via syscall ...
sim.run()
print(out.getvalue())  # the bytes the guest wrote; the real terminal stays silent

Feeding guest input

import io
from x86sim import Machine

sim = Machine(stdin=io.BytesIO(b"hello"))
# ... load a guest that does read(0, buf, n) via syscall ...
sim.run()
# the guest buffer now contains b"hello"

Enabling the glibc-startup syscalls

from x86sim import Machine

sim = Machine(glibc=True)
# ... load a guest that calls brk / anonymous mmap (e.g. via malloc) ...
sim.run()  # glibc syscalls succeed; with Machine() (glibc=False) they would raise

Running a real glibc binary

A static, non-PIE glibc executable can run end to end once you build its initial stack (argc/argv/envp and the auxiliary vector — see tests/python/elfload.py for a reference loader). It runs on either core:

import io
from x86sim import Machine

out = io.BytesIO()
sim = Machine(glibc=True, stdout=out, readlink=lambda p: "/hello")
# ... map the ELF's PT_LOAD segments and lay out the argc/argv/envp/auxv stack ...
sim.run()  # __libc_start_main -> main -> write(1, ...) -> exit_group
print(out.getvalue())

Working with Registers

# Set register values
sim.registers.rax = 0xdeadbeef

# Get register values
rip = sim.registers["rip"]
print(f"RIP: {rip:#x}")

Handling Exceptions

The simulator provides detailed exceptions for various fault conditions, such as PageFaultException, InvalidOpcodeException, etc. These can be caught and handled appropriately. In case that the address space of the simulator was populated with an ELF binary that contains debugging information, the exception will contain the file and linenoand line attributes that can be used to provide more context about the fault. Either all three attributes are present or none of them.

try:
    sim.run()
except RaspsimException as e:
    print(f"Simulation error: {e}")
    if hasattr(e, 'lineno'):
        print(f"At {e.file}:{e.lineno}: {e.line}")

Command-Line Interface

You can use x86sim as a command-line tool to simulate code directly from the terminal.

python -m x86sim << EOF
.global _start
.intel_syntax noprefix
.text
_start:
    mov rax, 1
    int 0x80
EOF

Contributing

Contributions are welcome! Please submit pull requests or open issues for any bugs or feature requests at the GitHub repository.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

x86sim-0.1.3.tar.gz (309.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

x86sim-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

x86sim-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

x86sim-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

x86sim-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

File details

Details for the file x86sim-0.1.3.tar.gz.

File metadata

  • Download URL: x86sim-0.1.3.tar.gz
  • Upload date:
  • Size: 309.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for x86sim-0.1.3.tar.gz
Algorithm Hash digest
SHA256 b2820a1815406a0139cf19c6595aaceaf852c8a257a2027e7af22a3d3fae55ad
MD5 dd01bdac90412d8b0f27c024d8fcebab
BLAKE2b-256 eff340e6f0dcc49e07ddd2359c06308e3881a95973c57593272c544dafcde25d

See more details on using hashes here.

Provenance

The following attestation bundles were made for x86sim-0.1.3.tar.gz:

Publisher: bindings.yml on rotmanjanez/x86sim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file x86sim-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for x86sim-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 0acc6ac555df28a94d784c1fbb97036eaf7d2b388d22b3c30620377f1ed6e5f8
MD5 d2e14dc1dd4638ce524cca74e0ecd5aa
BLAKE2b-256 6b747c8d27e9b13b0af18b99b82ece442aa4d172076ac6ef21c4a26ab428bec2

See more details on using hashes here.

Provenance

The following attestation bundles were made for x86sim-0.1.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: bindings.yml on rotmanjanez/x86sim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file x86sim-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for x86sim-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 abfb4a8ae97c919e2dffccd7905b786e97fd3bed5472010b06e776082fe2f253
MD5 76d05c88632a53a6bc8f56bbf4b19da5
BLAKE2b-256 dd668a011512e55f7e18f957d65a1c8bfc9961335115648492c6322e4d0fc420

See more details on using hashes here.

Provenance

The following attestation bundles were made for x86sim-0.1.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: bindings.yml on rotmanjanez/x86sim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file x86sim-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for x86sim-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 3664011e31afaf0fd958764716f11608b5f38a51b5771417f26ef3536c2beb5b
MD5 af4ba91c010d84d2eb42ee8542b7bcfa
BLAKE2b-256 6c9634cd012247a8143e147cf7d4f9d200ccf83cc4a9a80b48db2d79197b09d6

See more details on using hashes here.

Provenance

The following attestation bundles were made for x86sim-0.1.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: bindings.yml on rotmanjanez/x86sim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file x86sim-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for x86sim-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 6c87a2c81194e1034b3b1ec2c62b5dceec1749b4ccdddd705d2c6fc86dd35b93
MD5 82bb4b2039089f974921d00ee04555a7
BLAKE2b-256 cffa83c145d31b4b1ae6aec56aa6a67203373d05cdff9bbe8074705a63adea07

See more details on using hashes here.

Provenance

The following attestation bundles were made for x86sim-0.1.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: bindings.yml on rotmanjanez/x86sim

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page