PYTHON-PTRACE(1)

πŸ“¦ version 0.9.9, in arch rolling

πŸ¦‹ PYTHON-PTRACE(1) β€” the python-ptrace manual, bestie edition πŸ¦‹

πŸ’– NAME πŸ’–

python-ptrace β€” python-ptrace Documentation [image: No Maintenance Intended] [image] <http://unmaintained.tech/>

Okay so first thing: this project is no longer maintained and is looking for a new maintainer. Not me casually dropping the emotional lore first 😭

python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to trace processes) written in Python. πŸ’…

python-ptrace is an opensource project written in Python under GNU GPLv2 license. It supports Python 3.6 and newer. 🫢


✨ FEATURES ✨

  • High level Python object API : PtraceDebugger and PtraceProcess
  • Able to control multiple processes: catch fork events on Linux
  • Read/write bytes to arbitrary address: take care of memory alignment and split bytes to cpu word
  • Execution step by step using ptrace_singlestep() or hardware interruption 3
  • Can use distorm <http://www.ragestorm.net/distorm/> disassembler
  • Dump registers, memory mappings, stack, etc.
  • Syscall tracer and parser <#syscall> (strace.py command)

Status: πŸ‘‘

  • Supported operating systems: Linux, FreeBSD, OpenBSD
  • Supported architectures: x86, x86_64 (Linux), PPC (Linux), ARM (Linux EAPI)

Missing features: πŸ’€

  • Symbols: it's not possible to break on a function or read a variable value
  • No C language support: debugger shows assembler code, not your C (C++ or other language) code!
  • No thread support

🌸 TABLE OF CONTENTS 🌸

Bestie, here’s the whole map, and then we immediately start walking through it. No cap. πŸ—ΊοΈ

🧚 Install python-ptrace 🧚

python-ptrace supports Python 3.6 and newer.

πŸ“¦ Linux packages πŸ“¦

See also python-ptrace on Python Package Index (PyPI) β€” <https://pypi.python.org/pypi/python-ptrace>

πŸ› οΈ Install from source πŸ› οΈ

🎁 Download tarball 🎁

Get the latest tarball at the Python Package Index (PyPI) β€” <https://pypi.python.org/pypi/python-ptrace>.

🌿 Download development version 🌿

Download the development version using Git:

git clone https://github.com/vstinner/python-ptrace.git

Browse python-ptrace source code β€” <https://github.com/vstinner/python-ptrace>.

🧩 Option dependency 🧩

πŸ’» Installation πŸ’»

Note: pip is strongly recommanded. 🫑

Type as root:

python3 setup.py install

Or using sudo program:

sudo python3 setup.py install

⚑ cptrace ⚑

For faster debug and to avoid ctypes, you can also install cptrace: Python binding of the ptrace() function written in C:

python3 setup_cptrace.py install

πŸ§ͺ Run tests πŸ§ͺ

πŸ§ͺ Run tests with tox πŸ§ͺ

To run all tests, just type:

tox

The tox project β€” <https://testrun.org/tox/latest/> β€” creates a clean virtual environment to run tests.

πŸ§ͺ Run tests manually πŸ§ͺ

Type:

python3 runtests.py
python3 test_doc.py

It's also possible to run a specific test:

PYTHONPATH=$PWD python3 tests/test_strace.py

πŸš€ python-ptrace usage πŸš€

πŸ‘‹ Hello World πŸ‘‹

Short example attaching a running process. It gets the instruction pointer, executes a single step, and gets the new instruction pointer:

import ptrace.debugger
import signal
import subprocess
import sys

def debugger_example(pid):
    debugger = ptrace.debugger.PtraceDebugger()

    print("Attach the running process %s" % pid)
    process = debugger.addProcess(pid, False)
    # process is a PtraceProcess instance
    print("IP before: %#x" % process.getInstrPointer())

    print("Execute a single step")
    process.singleStep()
    # singleStep() gives back control to the process. We have to wait
    # until the process is trapped again to retrieve the control on the
    # process.
    process.waitSignals(signal.SIGTRAP)
    print("IP after: %#x" % process.getInstrPointer())

    process.detach()
    debugger.quit()

def main():
    args = [sys.executable, '-c', 'import time; time.sleep(60)']
    child_popen = subprocess.Popen(args)
    debugger_example(child_popen.pid)
    child_popen.kill()
    child_popen.wait()

if __name__ == "__main__":
    main()

🧠 API 🧠

🫢 PtraceProcess 🫢

The PtraceProcess class is an helper to manipulate a traced process.

Example:

tracer = PtraceProcess(pid)              # attach the process
tracer.singleStep()                      # execute one instruction
tracer.cont()                            # continue execution
tracer.syscall()                         # break at next syscall
tracer.detach()                          # detach process

# Get status
tracer.getreg('al')                      # get AL register value
regs = tracer.getregs()                  # read all registers
bytes = tracer.readBytes(regs.ax, 10)    # read 10 bytes
tracer.dumpCode()                        # dump code (as assembler or hexa is the disassembler is missing)
tracer.dumpStack()                       # dump stack (memory words around ESP)

# Modify the process
shellcode = '...'
ip = tracer.getInstrPointer()            # get EIP/RIP register
bytes = tracer.writeBytes(ip, shellcode) # write some bytes
tracer.setreg('ebx', 0)                  # set EBX register value to zero

Read ptrace/debugger/process.py source code to see more methods.

πŸ“ž Trace system calls (syscalls) πŸ“ž

python-ptrace can trace system calls using PTRACE_SYSCALL.

🧚 PtraceSyscall 🧚

ptrace.syscall module contains PtraceSyscall class: it's a parser of Linux syscalls similar to strace program.

Example:

connect(5, <sockaddr_in sin_family=AF_INET, sin_port=53, sin_addr=212.27.54.252>, 28) = 0
open('/usr/lib/i686/cmov/libcrypto.so.0.9.8', 0, 0 <read only>) = 4
mmap2(0xb7e87000, 81920, 3, 2066, 4, 297) = 0xb7e87000
rt_sigaction(SIGWINCH, 0xbfb7d4a8, 0xbfb7d41c, 8) = 0

You can get more information: result type, value address, argument types, and argument names.

Examples:

long open(const char* filename='/usr/lib/i686/cmov/libcrypto.so.0.9.8' at 0xb7efc027, int flags=0, int mode=0 <read only>) = 4
long fstat64(unsigned long fd=4, struct stat* buf=0xbfa46e2c) = 0
long set_robust_list(struct robust_list_head* head=0xb7be5710, size_t len_ptr=12) = 0

πŸ•΅οΈ strace.py πŸ•΅οΈ

Program strace.py is very close to strace program: display syscalls of a program. Example:

✨ Features (strace.py edition) ✨

  • Nice output of signal: see [[signal|python-ptrace signal handling]]
  • Supports multiple processes
  • Can trace running process
  • Can display arguments name, type and address
  • Option --filename to show only syscall using file names
  • Option --socketcall to show only syscall related to network (socket usage)
  • Option --syscalls to list all known syscalls

πŸ“ Example (strace.py edition) πŸ“

$ ./strace.py /bin/ls
execve(/bin/ls, [['/bin/ls'],|[/* 40 vars */]]) = 756
brk(0)                                   = 0x0805c000
access('/etc/ld.so.nohwcap', 0)          = -2 (No such file or directory)
mmap2(NULL, 8192, 3, 34, -1, 0)          = 0xb7f56000
access('/etc/ld.so.preload', 4)          = -2 (No such file or directory)
(...)
close(1)                                 = 0
munmap(0xb7c5c000, 4096)                 = 0
exit_group(0)
---done---

πŸ’… Options (strace.py edition) πŸ’…

The program has many options. Example with --socketcall (display only network functions):

$ ./strace.py --socketcall nc localhost 8080
execve(/bin/nc, [['/bin/nc',|'localhost', '8080']], [[/*|40 vars */]]) = 12948
socket(AF_FILE, SOCK_STREAM, 0)          = 3
connect(3, <sockaddr_un sun_family=AF_FILE, sun_path=/var/run/nscd/socket>, 110) = -2 (No such file or directory)
socket(AF_FILE, SOCK_STREAM, 0)          = 3
connect(3, <sockaddr_un sun_family=AF_FILE, sun_path=/var/run/nscd/socket>, 110) = -2 (No such file or directory)
socket(AF_INET, SOCK_STREAM, 6)          = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, 3217455272L, 4) = 0
connect(3, <sockaddr_in sin_family=AF_INET, sin_port=8080, sin_addr=127.0.0.1>, 16) = -111 (Connection refused)
(...)

πŸ› gdb.py πŸ›

gdb.py is a command line debugger similar to gdb, but with fewer features: no symbol support, no C language support, no thread support, etc.

πŸ•ΉοΈ Some commands πŸ•ΉοΈ

  • cont: continue execution
  • stepi: execute one instruction
  • step: execute one instruction, but don't enter into calls

Type help to list all available commands.

🌟 Features (gdb.py edition) 🌟

  • print command displays value as decimal and hexadecimal, but also the related memory mapping (if any):
(gdb) print $eip
Decimal: 3086383120
Hexadecimal: 0xb7f67810
Address is part of mapping: 0xb7f67000-0xb7f81000 => /lib/ld-2.6.1.so (r-xp)
  • Nice output of signal: see [[signal|python-ptrace signal handling]]
  • Syscall tracer with command "sys": see python-ptrace system call tracer <syscall>. Short example:
(gdb) sys
long access(char* filename='/etc/ld.so.nohwcap' at 0xb7f7f35b, int mode=F_OK) = -2 (No such file or directory)
  • Supports multiple processes:
(gdb) proclist
<PtraceProcess #24187> (active)
<PtraceProcess #24188>
(gdb) proc
Process ID: 24187 (parent: 24182)
Process state: T (traced)
Process command line: [['tests/fork_execve']
(...)
(gdb)|switch; proc
Switch to <PtraceProcess #24188>
Process ID: 24188 (parent: 24187)
Process state: T (traced)
Process command line: ['/bin/ls']]
(...)
  • Allow multiple commands on the same line using ";" separator:
(gdb) print $eax; set $ax=0xdead; print $eax
Decimal: 0
Hexadecimal: 0x00000000
Set $ax to 57005
Decimal: 57005
Hexadecimal: 0x0000dead
  • Only written in pure Python code, so it's easy to extend
  • Expression parser supports all arithmetic operator (a+b, a/b, a<<b, a&b, ...), parenthesis, use of registers, etc. and pointer dereference (ex: print *($ebx+0xc)).

πŸ–ΌοΈ Screenshot

ok bestie, real talk β€” here's what an actual live session looks like, in all its glory ✨

$ ./gdb.py ls
execve(/bin/ls, [['/bin/ls'],|[/* 40 vars */]]) = 16182
(gdb) where
ASM 0xb7f47810: MOV EAX, ESP <==
ASM 0xb7f47812: CALL 0xb7f47a60
ASM 0xb7f47817: MOV EDI, EAX
ASM 0xb7f47819: CALL 0xb7f47800
(gdb) regs
     EBX = 0xb7f4781e
     ECX = 0x0001d2f4
     EDX = 0xb7f61ff4
     ESI = 0x00000000
     (...)
(gdb) proc
Process ID: 16182
Process command line: [['/bin/ls']
Process|environment: ['TERM=xterm', 'SHELL=/bin/bash', (...)]]
Process working directory: /home/vstinner/prog/fusil/ptrace/trunk
(gdb) stack
STACK: 0xbfc58000..0xbfc6e000
STACK -8: 0x00000000
STACK -4: 0xb7f4781e
STACK +0: 0x00000001
STACK +4: 0xbfc6c6bb
STACK +8: 0x00000000
(gdb) maps
MAPS: 08048000-0805b000 r-xp 00000000 08:03 2588939    /bin/ls
MAPS: 0805b000-0805c000 rw-p 00012000 08:03 2588939    /bin/ls
(...)
MAPS: b7f61000-b7f63000 rw-p 00019000 08:03 1540553    /lib/ld-2.6.1.so
MAPS: bfc58000-bfc6e000 rw-p bfc58000 00:00 0          [[stack]
MAPS:|ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]]
(gdb) quit
Quit.
Terminate <PtraceProcess pid=16182>
Quit gdb.

like… she's literally doing the most and doing it flawlessly πŸ’…


πŸ’« python-ptrace process events

Process events

every single process event is built on the ProcessEvent class β€” she's the blueprint, the moment, the mother of them all πŸ‘‘

  • ProcessExit: the process exited with an exitcode, got killed by a signal, or exited abnormally
  • ProcessSignal: the process received a signal
  • NewProcessEvent: a new process got created, e.g. after a fork() syscall

Attributes (the little details that matter):

  • all events have a "process" attribute
  • ProcessExit has "exitcode" and "signum" attributes (both can be None)
  • ProcessSignal has "signum" and "name" attributes

for NewProcessEvent, hop over to the process.parent attribute to grab the parent process 🫢

πŸ’‘ Note: ProcessSignal has a display() method that shows off its content. Call it right after you receive the message, because it reads process memory to figure out why the signal was sent β€” so the tea goes stale fast.

Wait for any process event

the most generic one is waitProcessEvent() β€” it waits for any process event at all (exit, signal, or new process):

event = debugger.waitProcessEvent()

if you want one or more specific signals, that's what the waitSignals() methods are for. call it with no argument and it waits for any signal. any event that isn't a signal gets raised as a Python exception. examples, bestie:

signal = debugger.waitSignals()
signal = debugger.waitSignals(SIGTRAP)
signal = debugger.waitSignals(SIGINT, SIGTERM)
πŸ’‘ Note: signal is a ProcessSignal object β€” use signal.signum to get the signal number.

Wait for a specific process events

want any event from one specific process? that's waitEvent():

event = process.waitEvent()

for one or more signals, use the waitSignals() method. no argument = waits for any signal. other process events get raised as a Python exception. examples:

signal = process.waitSignals()
signal = process.waitSignals(SIGTRAP)
signal = process.waitSignals(SIGINT, SIGTERM)
πŸ’‘ Note: just like debugger.waitSignals(), signal is a ProcessSignal object.

🚦 python-ptrace signal handling

Introduction

PtraceSignal genuinely tries to serve useful info whenever a signal comes through. depending on which signal number it is, it shows you different things 🌈

it takes the current instruction, decoded as assembler code, to figure out why the signal got raised.

only Intel x86 (i386, maybe x86_64) is supported rn, sorry to the rest of the architectures 😭

when a process receives a signal, python-ptrace tries to explain why the signal was emitted.

General information (heads up: not shown for all signals, e.g. not for SIGABRT):

  • the CPU instruction that caused the crash
  • the CPU registers related to the crash
  • the memory mappings of the memory addresses

Categorize signals:

  • SIGFPE
    • Division by zero
  • SIGSEGV, SIGBUS
    • Invalid memory read
    • Invalid memory write
    • Stack overflow
    • Invalid memory access
  • SIGABRT
    • Program abort
  • SIGCHLD
    • Child process exit

Examples

βž— Division by zero (SIGFPE)

Signal: SIGFPE
Division by zero
- instruction: IDIV DWORD [[EBP-0x8]
- register ebp=0xbfdc4a98

πŸ™ˆ Invalid memory read/write (SIGSEGV)

Signal: SIGSEGV
Invalid read from 0x00000008
- instruction: MOV EAX, [EAX+0x8]]
- mapping: 0x00000008 is not mapped in memory
- register eax=0x00000000

PID: 23766
Signal: SIGSEGV
Invalid write to 0x00000008 (size=4 bytes)
- instruction: MOV DWORD [[EAX+0x8],|0x2a
- mapping: 0x00000008..0x0000000b is not mapped in memory
- register eax=0x00000000

Given information β€” here's what you're getting, no cap:

  • address of the segmentation fault
  • (if possible) the size of the invalid memory read/write
  • the CPU instruction that caused the crash
  • the CPU registers related to the crash
  • the memory mappings of the related memory address

πŸ’€ Stack overflow (SIGSEGV)

Signal: SIGSEGV
STACK OVERFLOW! Stack pointer is in 0xbf534000-0xbfd34000 => [stack]] (rw-p)
- instruction: MOV BYTE [[EBP-0x1004],|0x0
- mapping: 0xbf533430 is not mapped in memory
- register <stack ptr>=0xbf533430
- register ebp=0xbf534448

πŸ‘Ά Child exit (SIGCHLD)

PID: 24008
Signal: SIGCHLD
Child process 24009 exited normally
Signal sent by user 1000

Information:

  • child process identifier
  • child process user identifier

Examples (the short round-up) ✨

Invalid read:

Signal: SIGSEGV
Invalid read from 0x00000008
- instruction: MOV EAX, [EAX+0x8]
- mapping: (no memory mapping)
- register eax=0x00000000

Invalid write (MOV):

Signal: SIGSEGV
Invalid write to 0x00000008 (size=4 bytes)
- instruction: MOV DWORD [EAX+0x8], 0x2a
- mapping: (no memory mapping)
- register eax=0x00000000

abort():

Signal: SIGABRT
Program received signal SIGABRT, Aborted.

Source code

go look, she's literally right there:

  • ptrace/debugger/ptrace_signal.py
  • ptrace/debugger/signal_reason.py

🐍 cptrace Python module

a Python binding for ptrace, written in C. tiny, powerful, iconic πŸ’œ

Example

dummy example, just vibes:

>>> import cptrace
>>> cptrace.ptrace(1, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: ptrace(request=1, pid=1, 0x(nil), 0x(nil)) error #1: Operation not permitted

πŸ‘‘ Authors

πŸ’– Contributors

  • Anthony Gelibert <anthony.gelibert AT me.com> β€” fix cptrace on Apple
  • Dimitris Glynos <dimitris AT census-labs.com> β€” follow gdb.py commands
  • Jakub Wilk <jwilk AT debian.org> β€” fix for GNU/kFreeBSD
  • Mark Seaborn <mrs AT mythic-beasts.com> β€” Create -i option for strace
  • MickaΓ«l GuΓ©rin aka KAeL <mickael.guerin AT crocobox.org> β€” OpenBSD port
  • teythoon β€” convert all classes to new-style classes
  • T. Bursztyka aka Tuna <tuna AT lyua.org> β€” x86_64 port
  • Victor Stinner <victor.stinner AT gmail.com> β€” python-ptrace author and maintainer

πŸ™ Thanks

  • procps authors (top and uptime programs)

πŸ“œ Changelog

python-ptrace 0.9.9 (2024-03-13)

  • Fix arguments of pipe/pipe2 system calls for proper display in call format. Patch by JosΓ© Pereira.
  • Introduced support for three-digit minor device IDs in PROC_MAP_REGEX. Patch by fab1ano.
  • Added RISCV (riscv32/riscv64) support. Patch by Andreas Schwab and vimer/yuzibo.
  • Fix stray exception raised by child processes terminating with exit code 255. Patch by Duane Voth/duanev.
  • Removed usage of the imp module. Collaboration between Mario Haustein/hamarituc and Stephen Kitt/skitt.

python-ptrace 0.9.8 (2021-03-17)

  • Added Arm 64bit (AArch64) support.
  • Implemented PTRACE_GETREGSET and PTRACE_SETREGSET required on AArch64 and available on Linux.
  • Issue #66: Fix SIGTRAP|0x80 or SIGTRAP wait in syscall_state.exit (PTRACE_O_TRACESYSGOOD).
  • The development branch master was renamed to main. See https://sfconservancy.org/news/2020/jun/23/gitbranchname/ for the rationale.

python-ptrace 0.9.7 (2020-08-10)

  • Add missing module to install directives
  • Update README.rst
  • Project back in beta and maintenance

python-ptrace 0.9.6 (2020-08-10)

  • Remove RUNNING_WINDOWS constant: python-ptrace doesn't not support Windows.
  • Drop Python 2.7 support. six dependency is no longer needed.
  • Add close_fds and pass_fds to createChild() function. Patch by Jean-Baptiste Skutnik.
  • Enhance strace.py output for open flags and open optional parameters. Patch by Jean-Baptiste Skutnik.
  • Add support for PowerPC 64-bit (ppc64). Patch by Jean-Baptiste Skutnik.

python-ptrace 0.9.5 (2020-04-13)

  • Fix readProcessMappings() for device id on 3 digits. Patch by Cat Stevens.
  • Drop Python 2 support.

python-ptrace 0.9.4 (2019-07-30)

python-ptrace 0.9.3 (2017-09-19)

  • Issue #42: Fix test_strace.py: tolerate the openat() syscall.

python-ptrace 0.9.2 (2017-02-12)

  • Issue #35: Fix strace.py when tracing multiple processes: use the correct process. Fix suggested by Daniel Trnka.

python-ptrace 0.9.1 (2016-10-12)

  • Added tracing of processes created with the clone syscall (commonly known as threads).
  • gdb.py: add gcore command, dump the process memory.
  • Allow command names without absolute path.
  • Fix ptrace binding: clear errno before calling ptrace().
  • Fix PtraceSyscall.exit() for unknown error code
  • Project moved to GitHub: https://github.com/haypo/python-ptrace
  • Remove the ptrace.ctypes_errno module: use directly the ctypes.get_errno() function
  • Remove the ptrace.ctypes_errno module: use directly ctypes.c_int8, ctypes.c_uint32, ... types

python-ptrace 0.9 (2016-04-23)

  • Add all Linux syscall prototypes
  • Add error symbols (e.g. ENOENT), in addition to error text, for strace
  • Fix open mode so O_RDONLY shows if it's the only file access mode
  • Python 3: fix formatting of string syscall arguments (ex: filenames), decode bytes from the locale encoding
  • Issue #17: syscall parser now supports O_CLOEXEC and SOCK_CLOEXEC, fix unit tests on Python 3.4 and newer

python-ptrace 0.8.1 (2014-10-30)

  • Update MANIFEST.in to include all files
  • Fix to support Python 3.5

πŸŽ€ python-ptrace 0.8 (2014-10-05)

  • Issue #9: no cap, they rewrote waitProcessEvent() and waitSignals() over in PtraceProcess so they stop calling waitpid() with pid=-1. Why? because there's a literal race condition between waitpid(-1) and fork β€” the status of the child process can come back before the debugger even finds out the new child process was created. chaos. 😭
  • Issue #10: fixed PtraceProcess.readBytes() for processes the debugger didn't create itself (ex: fork) for when the kernel blocks access to private mappings of /proc/pid/mem. The glow-up: fall back to PTRACE_PEEKTEXT, which is slower but a debugger tracing the process is always allowed to use it. slow but legal, we love that for us πŸ’…

🌸 python-ptrace 0.7 (2013-03-05)

  • experimental support of Python 3.3 in the same code base πŸ¦‹
  • dropped support of Python 2.5 (rip bozo)
  • removed the ptrace.compatibility module
  • fixed Process.readStruct() and Process.readArray() on x86_64
  • experimental support of ARM architecture (Linux EAPI) β€” strace.py has been tested on Raspberry Pi (armv6l) πŸ“

⭐ python-ptrace 0.6.6 (2013-12-16)

  • fixed os_tools.RUNNING_LINUX for Python 2.x compiled on Linux kernel 3.x
  • FreeBSD on x86_64 is supported now πŸŽ€
  • added the missing prototype of the unlinkat() system call. patch written by Matthew Fernandez β€” ty bestie 🫢

πŸ’œ python-ptrace 0.6.5 (2013-06-06)

  • syscall: fixed parsing socketcall on Linux x86
  • syscall: fixed the prototype of socket()

✨ python-ptrace 0.6.4 (2012-02-26)

  • converted all classes to new-style classes, patch written by teythoon
  • fixed compilation on Apple, patch written by Anthony Gelibert 🍎
  • GNU/kFreeBSD support, patch written by Jakub Wilk
  • sockaddr_in6 (IPv6 address) support β€” hi bestie in six dimensions 🌈

πŸ¦‹ python-ptrace 0.6.3 (2011-02-16)

  • support distrom3
  • Python 3 support (era-defining, honestly)
  • renamed strace.py option --socketcall to --socket, and fixed this option for FreeBSD and Linux/64 bits
  • added MANIFEST.in: include all files in source distribution (tests, cptrace module, ...) πŸ“¦

πŸ“ python-ptrace 0.6.2 (2009-11-09)

  • fixed 64 bits sub registers (set mask for eax, ebx, ecx, edx)

πŸ‘‘ python-ptrace 0.6.1 (2009-11-07)

  • created follow, showfollow, resetfollow, xray commands in gdb.py. patch written by Dimitris Glynos
  • project website moved to: http://bitbucket.org/haypo/python-ptrace/
  • replaced types (u)intXX_t by c_(u)intXX
  • created MemoryMapping.search() method, and MemoryMapping now keeps a weak reference to the process (clingy but in a healthy way)

πŸ’– python-ptrace 0.6 (2009-02-13)

User visible changes:

  • python-ptrace now depends on Python 2.5
  • invalid memory access: add the fault address in the name
  • updated the Python 3.0 conversion patch
  • created -i (--show-ip) option for strace.py: shows the instruction pointer
  • added a new example (itrace.py) written by Mark Seaborn and based on strace.py

API changes:

  • PtraceSyscall: store the instruction pointer at syscall enter (if the option instr_pointer=True, disabled by default)
  • removed PROC_DIRNAME and procFilename() from ptrace.linux_proc

Bugfixes:

  • fixed locateProgram() for relative path
  • fixed interpretation of memory fault on the MOSVW instruction (source is ESI and destination is EDI, and not the inverse!) πŸ™ˆ

🌈 python-ptrace 0.5 (2008-09-13)

Visible changes:

  • wrote an example (the most simple debugger) and began to document the code
  • gdb.py: created "dbginfo" command
  • parse socket syscalls on FreeBSD
  • on invalid memory access (SIGSEGV), eval the dereference expression to get the fault address on OS without siginfo (e.g. FreeBSD)
  • fixes to get minimal Windows support: fix imports, fix locateProgram()

Other changes:

  • break the API, periodt:
    • rename PtraceDebugger.traceSysgood() to PtraceDebugger.enableSysgood()
    • rename PtraceDebugger.trace_sysgood to PtraceDebugger.use_sysgood
    • remove PtraceProcess.readCode()
  • created createChild() function which close all files except stdin, stdout and stderr
  • on FreeBSD, on process exit recalls waitpid(pid) to avoid zombi process 🧟

πŸŽ€ python-ptrace 0.4.2 (2008-08-28)

  • BUGFIX: fixed a typo in gdb.py (commands => command_str) β€” it wasn't possible to write more than one command... the way that bugs in typos ruin everything 😭
  • BUGFIX: fixed a typo in SignalInfo class (remove "self."). When a process received a signal SIGCHLD (because of a fork), the debugger exited because of this bug. iconic fail tbh
  • BUGFIX: Debugger._wait() returns abnormal process exit as a normal event, the event is not raised as an exception
  • PtraceSignal: don't clear preformatted arguments (e.g. arguments of execve)

πŸ¦‹ python-ptrace 0.4.1 (2008-08-23)

  • the project has a new dedicated website: http://python-ptrace.hachoir.org/ ✨
  • created cptrace: optional Python binding of ptrace written in C (faster than ptrace, the Python binding written in Python with ctypes)
  • added name attribute to SignalInfo classes
  • fixes to help Python 3.0 compatibility: don't use sys.exc_clear() (was useless) in writeBacktrace()
  • ProcessState: created utime, stime, starttime attributes

πŸ’… python-ptrace 0.4.0 (2008-08-19)

Visible changes:

  • renamed the project to "python-ptrace" (old name was "Ptrace)
  • strace.py: created --ignore-regex option
  • PtraceSignal: support SIGBUS, display the related registers and the instruction
  • support execve() syscall tracing

Developer changes:

  • the new API is incompatible with 0.3.2 (glow-up, not a downgrade)
  • PtraceProcess.waitProcessEvent() accepts optional blocking=False argument
  • PtraceProcess.getreg()/setreg() are able to read/write i386 and x86-64 "sub-registers" like al or bx
  • removed iterProc() function, replaced by openProc() with explicit call to .close() to make sure that files are closed
  • created searchProcessesByName()
  • replaced CPU_PPC constant by CPU_POWERPC and created CPU_PPC32 and CPU_PPC64
  • created MemoryMapping object, used by readMappings() and findStack() methods of PtraceProcess
  • always define all PtraceProcess methods but raise an error if the function is not implemented

πŸ”₯ TODO πŸ”₯

Main tasks

Minor tasks

  • fix gdb.py "step" command on a jump. Example where step will never stop:
(gdb) where
ASM 0xb7e3b917: JMP 0xb7e3b8c4 (eb ab)
ASM 0xb7e3b919: LEA ESI, [ESI+0x0] (8db426 00000000)
not all of this is done, bestie β€” it's a wishlist, not a receipt πŸ’€

Project using python-ptrace

python-ptrace announces

ptrace usage

Similar projects

Interesting articles


🌸 Author 🌸

Victor Stinner β€” the main character who wrote all of this πŸ‘‘

2014, Victor Stinner


okay that's the whole page bestie, you made it to the end πŸŽ‰ this little beauty is version 0.9.9, dated Dec 14, 2025, and you can find it filed under PYTHON-PTRACE(1) β€” the way that it's still serving looks after all these years, we love a legacy icon 🫢✨ go forth and trace some processes fr fr πŸ’…

πŸ“¦ where this page comes from