python-ptrace-0.9.3/ 0000775 0001750 0001750 00000000000 13160156527 014612 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/gdb.py 0000775 0001750 0001750 00000072347 13047323324 015733 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
from __future__ import print_function
from ptrace import PtraceError
from ptrace.debugger import (PtraceDebugger, Application,
ProcessExit, NewProcessEvent, ProcessSignal,
ProcessExecution, ProcessError)
from optparse import OptionParser
from os import getpid
from sys import stdout, stderr, exit
from logging import getLogger, info, warning, error
from ptrace.version import VERSION, WEBSITE
from ptrace.error import PTRACE_ERRORS, writeError
from ptrace.binding import HAS_PTRACE_SINGLESTEP
from ptrace.disasm import HAS_DISASSEMBLER
from ptrace.ctypes_tools import (truncateWord,
formatWordHex, formatAddress, formatAddressRange, word2bytes)
from ptrace.process_tools import dumpProcessInfo
from ptrace.tools import inverseDict
from ptrace.func_call import FunctionCallOptions
from ptrace.signames import signalName, SIGNAMES
from ptrace.six import PY3, binary_type
from signal import SIGTRAP, SIGINT
from ptrace.terminal import enableEchoMode, terminalWidth
from errno import ESRCH
from ptrace.cpu_info import CPU_POWERPC
from ptrace.debugger import ChildError
from ptrace.debugger.memory_mapping import readProcessMappings
from ptrace.os_tools import RUNNING_PYTHON3
try:
unichr
raw_input
except NameError:
# Python 3
unichr = chr
raw_input = input
import re
if stdout.isatty():
try:
# Use readline for better raw_input()
import readline # noqa
except ImportError:
pass
# Match a register name: $eax, $gp0, $orig_eax
REGISTER_REGEX = re.compile(r"\$[a-z]+[a-z0-9_]+")
# BYTES_REGEX = re.compile(r"""(?:'([^'\\]*)'|"([^"\\]*)")""")
SIGNALS = inverseDict(SIGNAMES) # name -> signum
COMMANDS = (
# trace instructions
("cont", "continue execution"),
("step", "execute one instruction (do not enter in a call)"),
("stepi", "execute one instruction (enter the call)"),
("until", "execute code until specified address (until
)"),
("set", "set register value (set =)"),
("sys", "continue execution to next syscall"),
("signal", "send a signal to the process (signal )"),
("signals", "display signals"),
# current process info
("regs", "display registers"),
("where", "display true code content (show breakpoints effects on code). e.g. 'where $eip', 'where $eip $eip+20'"),
("print", "display a value (print )"),
("hexdump", "dump memory as specified address or address range (hexdump or hexdump )"),
("gcore", "generate core file of the process"),
("where2", "display original code content (don't show effects of breakpoint on code)"),
("stack", "display stack content"),
("backtrace", "dump the backtrace"),
("proc", "display process information"),
("maps", "display memory mappings"),
# breakpoints
("break", "set a breakpoint (break )"),
("breakpoints", "display breakpoints"),
("delete", "delete a breakpoint (delete )"),
# processes
("attach", 'attach a new process (e.g. "attach 2390")'),
("proclist", "list of traced processes"),
("switch", "switch active process (switch or switch )"),
("follow", r'''follow a term (e.g. "follow '\x12\x14\x27\x13'")'''),
("showfollow", 'show all "followed" terms'),
("resetfollow", 'reset all "followed" terms'),
("xray", 'show addresses of (and possible pointers to) "followed" terms'),
# other
("dbginfo", "information about the debugger"),
("quit", "quit debugger"),
("help", "display this help"),
)
def formatAscii(data):
def asciiChar(byte):
if 32 <= byte <= 126:
return unichr(byte)
else:
return '.'
if RUNNING_PYTHON3:
return u''.join(asciiChar(byte) for byte in data)
else:
return u''.join(asciiChar(ord(byte)) for byte in data)
def formatHexa(data):
if RUNNING_PYTHON3:
return u' '.join(u"%02x" % byte for byte in data)
else:
return u' '.join(u"%02x" % ord(byte) for byte in data)
# finds possible pointer values in process memory space,
# pointing to address
def getPointers(process, address):
address = word2bytes(address)
procmaps = readProcessMappings(process)
for pm in procmaps:
for found in pm.search(address):
yield found
class Gdb(Application):
def __init__(self):
Application.__init__(self)
# Parse self.options
self.parseOptions()
# Setup output (log)
self.setupLog()
self.last_signal = {}
# We assume user wants all possible information
self.syscall_options = FunctionCallOptions(
write_types=True,
write_argname=True,
write_address=True,
)
# FIXME: Remove self.breaks!
self.breaks = dict()
self.followterms = []
def setupLog(self):
self._setupLog(stdout)
def parseOptions(self):
parser = OptionParser(
usage="%prog [options] -- program [arg1 arg2 ...]")
self.createCommonOptions(parser)
self.createLogOptions(parser)
self.options, self.program = parser.parse_args()
if self.options.pid is None and not self.program:
parser.print_help()
exit(1)
self.processOptions()
self.show_pid = self.options.fork
def _continueProcess(self, process, signum=None):
if not signum and process in self.last_signal:
signum = self.last_signal[process]
if signum:
error("Send %s to %s" % (signalName(signum), process))
process.cont(signum)
try:
del self.last_signal[process]
except KeyError:
pass
else:
process.cont()
def cont(self, signum=None):
for process in self.debugger:
process.syscall_state.clear()
if process == self.process:
self._continueProcess(process, signum)
else:
self._continueProcess(process)
# Wait for a process signal
signal = self.debugger.waitSignals()
process = signal.process
# Hit breakpoint?
if signal.signum == SIGTRAP:
ip = self.process.getInstrPointer()
if not CPU_POWERPC:
# Go before "INT 3" instruction
ip -= 1
breakpoint = self.process.findBreakpoint(ip)
if breakpoint:
error("Stopped at %s" % breakpoint)
breakpoint.desinstall(set_ip=True)
else:
self.processSignal(signal)
return None
def readRegister(self, regs):
name = regs.group(0)[1:]
value = self.process.getreg(name)
return str(value)
def parseInteger(self, text):
# Remove spaces and convert to lower case
text = text.strip()
if " " in text:
raise ValueError("Space are forbidden: %r" % text)
text = text.lower()
# Replace registers by their value
orig_text = text
text = REGISTER_REGEX.sub(self.readRegister, text)
# Replace hexadecimal numbers by decimal numbers
def readHexadecimal(regs):
text = regs.group(0)
if text.startswith("0x"):
text = text[2:]
elif not re.search("[a-f]", text):
return text
value = int(text, 16)
return str(value)
text = re.sub(r"(?:0x)?[0-9a-f]+", readHexadecimal, text)
# Reject invalid characters
if not re.match(r"^[()<>+*/&0-9-]+$", text):
raise ValueError("Invalid expression: %r" % orig_text)
# Use integer division (a//b) instead of float division (a/b)
text = text.replace("/", "//")
# Finally, evaluate the expression
is_pointer = text.startswith("*")
if is_pointer:
text = text[1:]
try:
value = eval(text)
value = truncateWord(value)
except SyntaxError:
raise ValueError("Invalid expression: %r" % orig_text)
if is_pointer:
value = self.process.readWord(value)
return value
def parseIntegers(self, text):
values = []
for item in text.split():
item = item.strip()
value = self.parseInteger(item)
values.append(value)
return values
def parseBytes(self, text):
# FIXME: Validate input
# if not BYTES_REGEX.match(text):
# raise ValueError('Follow text must be enclosed in quotes!')
if PY3:
text = 'b' + text.lstrip()
value = eval(text)
if not isinstance(value, binary_type):
raise TypeError("Input is not a bytes string!")
return value
def addFollowTerm(self, text):
# Allow terms of the form 'string', "string", '\x04', "\x01\x14"
term = self.parseBytes(text)
self.followterms.append(term)
def showFollowTerms(self):
print(self.followterms)
def _xray(self):
for term in self.followterms:
for process in self.debugger:
for procmap in readProcessMappings(process):
for address in procmap.search(term):
yield (process, procmap, address, term)
# displays the offsets of all terms found in the process memory mappings
# along with possible addresses of pointers pointing to these terms
def xray(self):
for process, procmap, address, term in self._xray():
pointers = " ".join(formatAddress(ptr_addr)
for ptr_addr in getPointers(process, address))
print("term[%s] pid[%i] %s %s pointers: %s" % (
repr(term), process.pid, procmap,
formatAddress(address),
pointers))
def execute(self, command):
errmsg = None
if command == "cont":
errmsg = self.cont()
elif command == "proc":
self.procInfo()
elif command == "proclist":
self.procList()
elif command.startswith("attach "):
errmsg = self.attachProcess(command[7:])
elif command == "regs":
self.process.dumpRegs()
elif command == "stack":
self.process.dumpStack()
elif command == "gcore":
self.gcore(self.process)
elif command == "backtrace":
errmsg = self.backtrace()
elif command == "where" or command.startswith("where "):
errmsg = self.where(command[6:])
elif command == "where2" or command.startswith("where2 "):
errmsg = self.where(command[7:], manage_bp=True)
elif command == "maps":
self.process.dumpMaps()
elif command == "dbginfo":
self.debuggerInfo()
elif command == "step":
errmsg = self.step(False)
elif command == "stepi":
errmsg = self.step(True)
elif command == "sys":
errmsg = self.syscallTrace()
elif command == "help":
self.help()
elif command.startswith("set "):
errmsg = self.set(command)
elif command.startswith("until "):
errmsg = self.until(command[6:])
elif command.startswith("switch") or command == "switch":
errmsg = self.switch(command[6:])
elif command.startswith("break "):
errmsg = self.breakpoint(command[6:])
elif command.startswith("breakpoints"):
self.displayBreakpoints()
elif command.startswith("signals"):
self.displaySignals()
elif command.startswith("delete "):
errmsg = self.delete(command[7:])
elif command.startswith("hexdump "):
errmsg = self.hexdump(command[8:])
elif command.startswith("signal "):
errmsg = self.signal(command[7:])
elif command.startswith("print "):
errmsg = self.print_(command[6:])
elif command.startswith("follow "):
errmsg = self.addFollowTerm(command[7:])
elif command == "showfollow":
self.showFollowTerms()
elif command == "resetfollow":
self.followterms = []
elif command == "xray":
self.xray()
else:
errmsg = "Unknown command: %r" % command
if errmsg:
print(errmsg, file=stderr)
return False
return True
def parseSignum(self, command):
try:
return SIGNALS[command]
except KeyError:
pass
try:
return SIGNALS["SIG" + command]
except KeyError:
pass
try:
return self.parseInteger(command)
except ValueError:
raise ValueError("Invalid signal number: %r" % command)
def signal(self, command):
try:
signum = self.parseSignum(command)
except ValueError as err:
return str(err)
last_process = self.process
try:
errmsg = self.cont(signum)
return errmsg
finally:
try:
del self.last_signal[last_process]
except KeyError:
pass
def print_(self, command):
try:
value = self.parseInteger(command)
except ValueError as err:
return str(err)
error("Decimal: %s" % value)
error("Hexadecimal: %s" % formatWordHex(value))
for map in self.process.readMappings():
if value not in map:
continue
error("Address is part of mapping: %s" % map)
return None
def gcore(self, process):
import re
childPid = str(process).split('#')[-1][:-1]
maps_file = open("/proc/" + childPid + "/maps", 'r')
mem_file = open("/proc/" + childPid + "/mem", 'r', 0)
from sys import argv
dump = open("/vmdump/" + argv[1] + ".dump", "wb")
for line in maps_file.readlines(): # for each mapped region
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
if m.group(3) == 'r': # if this is a readable region
if "/lib" not in line and "/usr" not in line: # for eliminating of shared libs
start = int(m.group(1), 16)
end = int(m.group(2), 16)
mem_file.seek(start) # seek to region start
chunk = mem_file.read(end - start) # read region contents
dump.write(chunk,) # dump contents to standard output
maps_file.close()
mem_file.close()
dump.close()
def hexdump(self, command):
max_line = 20
width = (terminalWidth() - len(formatAddress(1)) - 3) // 4
width = max(width, 1)
limited = None
parts = command.split(" ", 1)
if 1 < len(parts):
try:
start_address = self.parseInteger(parts[0])
end_address = self.parseInteger(parts[1])
if end_address <= start_address:
raise ValueError('End address (%s) is smaller than start address(%s)!'
% (formatAddress(end_address), formatAddress(start_address)))
except ValueError as err:
return str(err)
size = end_address - start_address
max_size = width * max_line
if max_size < size:
limited = max_size
end_address = start_address + max_size
else:
try:
start_address = self.parseInteger(command)
except ValueError as err:
return str(err)
end_address = start_address + 5 * width
read_error = None
address = start_address
while address < end_address:
size = min(end_address - address, width)
try:
# Read bytes
memory = self.process.readBytes(address, size)
# Format bytes
hexa = formatHexa(memory)
hexa = hexa.ljust(width * 3 - 1, ' ')
ascii = formatAscii(memory)
ascii = ascii.ljust(width, ' ')
# Display previous read error, if any
if read_error:
warning("Warning: Unable to read memory %s" % (
formatAddressRange(*read_error)))
read_error = None
# Display line
error("%s| %s| %s" % (formatAddress(address), hexa, ascii))
except PtraceError:
if not read_error:
read_error = [address, address + size]
else:
read_error[1] = address + size
address += size
# Display last read error, if any
if read_error:
warning("Warning: Unable to read memory %s" % (
formatAddressRange(*read_error)))
if limited:
warning("(limit to %s bytes)" % max_size)
return None
def backtrace(self):
trace = self.process.getBacktrace()
for func in trace:
error(func)
if trace.truncated:
error("--limited to depth %s--" % len(trace))
return None
def where(self, command, manage_bp=False):
start = None
stop = None
try:
values = self.parseIntegers(command)
except ValueError as err:
return str(err)
if 1 <= len(values):
start = values[0]
if 2 <= len(values):
stop = values[1]
self.process.dumpCode(start, stop, manage_bp=manage_bp)
return None
def procInfo(self):
dumpProcessInfo(error, self.process.pid, max_length=160)
def procList(self):
for process in self.debugger:
text = str(process)
if self.process == process:
text += " (active)"
error(text)
def set(self, command):
try:
key, value = command[4:].split("=", 1)
key = key.strip().lower()
if not key.startswith("$"):
return 'Register name (%s) have to start with "$"' % key
key = key[1:]
except ValueError as err:
return "Invalid command: %r" % command
try:
value = self.parseInteger(value)
except ValueError as err:
return str(err)
try:
self.process.setreg(key, value)
except ProcessError as err:
return "Unable to set $%s=%s: %s" % (key, value, err)
error("Set $%s to %s" % (key, value))
return None
def displayInstr(self, prefix):
try:
if HAS_DISASSEMBLER:
instr = self.process.disassembleOne()
error("%s %s: %s" % (
prefix, formatAddress(instr.address), instr.text))
else:
self.process.dumpCode()
except PtraceError as err:
error("Unable to read current instruction: %s" % err)
def attachProcess(self, text):
try:
pid = self.parseInteger(text)
except ValueError as err:
return str(err)
process = self.debugger.addProcess(pid, False)
self.switchProcess(process)
def step(self, enter_call, address=None):
if address is None:
self.displayInstr("Execute")
if (not HAS_PTRACE_SINGLESTEP) or (not enter_call):
if address is None:
address = self.process.getInstrPointer()
size = self.readInstrSize(address, default_size=None)
if not size:
return "Unable to read instruction size at %s" \
% formatAddress(address)
address += size
size = self.readInstrSize(address)
# Set a breakpoint
breakpoint = self.process.createBreakpoint(address, size)
# Continue the process
self.process.cont()
else:
# Use ptrace single step command
self.process.singleStep()
breakpoint = None
# Execute processus until next TRAP
try:
self.process.waitSignals(SIGTRAP)
if breakpoint:
breakpoint.desinstall(set_ip=True)
except:
if breakpoint:
breakpoint.desinstall()
raise
return None
def newProcess(self, event):
error("New process: %s" % event.process)
# FIXME: This function doesn't work with multiple processes
# especially when a parent waits for a child
def syscallTrace(self):
# Trace until syscall enter
self.process.syscall()
self.process.waitSyscall()
# Process the syscall event
state = self.process.syscall_state
syscall = state.event(self.syscall_options)
# Display syscall
if syscall:
if syscall.result is not None:
text = "%s = %s" % (syscall.format(), syscall.result_text)
if self.show_pid:
text = "Process %s exits %s" % (syscall.process.pid, text)
error(text)
else:
text = syscall.format()
if self.show_pid:
text = "Process %s enters %s" % (syscall.process.pid, text)
error(text)
return None
def until(self, command):
try:
address = self.parseInteger(command)
except ValueError as err:
return str(err)
errmsg = self.step(False, address)
if errmsg:
return errmsg
self.displayInstr("Current")
return None
def switch(self, command):
if not command:
process_list = self.debugger.list
if len(process_list) == 1:
return "There is only one process!"
index = process_list.index(self.process)
index = (index + 1) % len(process_list)
process = process_list[index]
self.switchProcess(process)
return
try:
pid = self.parseInteger(command)
except ValueError as err:
return str(err)
try:
process = self.debugger[pid]
self.switchProcess(process)
except KeyError:
return "There is not process %s" % pid
return None
def switchProcess(self, process):
if self.process == process:
return
error("Switch to %s" % process)
self.process = process
def nextProcess(self):
try:
process = next(iter(self.debugger))
self.switchProcess(process)
except StopIteration:
pass
def displayBreakpoints(self):
found = False
for process in self.debugger:
for bp in process.breakpoints.values():
found = True
error("%s:%s" % (process, bp))
if not found:
error("(no breakpoint)")
def displaySignals(self):
signals = list(SIGNAMES.items())
signals.sort(key=lambda key_value: key_value[0])
for signum, name in signals:
error("% 2s: %s" % (signum, name))
def readInstrSize(self, address, default_size=None):
if not HAS_DISASSEMBLER:
return default_size
try:
# Get address and size of instruction at specified address
instr = self.process.disassembleOne(address)
return instr.size
except PtraceError as err:
warning("Warning: Unable to read instruction size at %s: %s" % (
formatAddress(address), err))
return default_size
def breakpoint(self, command):
try:
address = self.parseInteger(command)
except ValueError as err:
return str(err)
# Create breakpoint
size = self.readInstrSize(address)
try:
bp = self.process.createBreakpoint(address, size)
except PtraceError as err:
return "Unable to set breakpoint at %s: %s" % (
formatAddress(address), err)
error("New breakpoint: %s" % bp)
return None
def delete(self, command):
try:
address = self.parseInteger(command)
except ValueError as err:
return str(err)
breakpoint = self.process.findBreakpoint(address)
if not breakpoint:
return "No breakpoint at %s " % formatAddress(address)
breakpoint.desinstall()
error("%s deleted" % breakpoint)
return None
def help(self):
for command, description in COMMANDS:
error("%s: %s" % (command, description))
error('')
error("Value can be an hexadecimal/decimal number or a register name ($reg)")
error("You can use operators a+b, a-b, a*b, a/b, a<>b, a**b, and parenthesis in expressions")
error(
'Use ";" to write multiple commands on the same line (e.g. "step; print $eax")')
def processSignal(self, event):
event.display()
self.switchProcess(event.process)
self.last_signal[self.process] = event.signum
error("%s interrupted by %s" % (self.process, event.name))
def processExecution(self, event):
error(event)
self.switchProcess(event.process)
self.interrupt()
def debuggerInfo(self):
error("Debugger process ID: %s" % getpid())
error("python-ptrace version %s" % VERSION)
error("Website: %s" % WEBSITE)
def interrupt(self):
waitlist = []
for process in self.debugger:
if process.is_stopped:
continue
try:
if process.isTraced():
continue
except NotImplementedError:
pass
warning("Interrupt %s (send SIGINT)" % process)
process.kill(SIGINT)
waitlist.append(process)
for process in waitlist:
info("Wait %s interruption" % process)
try:
process.waitSignals(SIGINT)
except ProcessSignal as event:
event.display()
except KeyboardInterrupt:
pass
def deleteProcess(self, pid):
try:
process = self.debugger[pid]
except KeyError:
return
event = process.processTerminated()
error(str(event))
if process == self.process:
self.nextProcess()
def restoreTerminal(self):
if enableEchoMode():
error("Terminal: restore echo mode")
def mainLoop(self):
# Read command
try:
self.restoreTerminal()
command = raw_input(self.invite).strip()
except EOFError:
print()
return True
except KeyboardInterrupt:
error("User interrupt!")
self.interrupt()
return False
# If command is empty, reuse previous command
if not command:
if self.previous_command:
command = self.previous_command
info("Replay previous command: %s" % command)
else:
return False
self.previous_command = None
# User wants to quit?
if command == "quit":
return True
# Execute the user command
try:
command_str = command
ok = True
for command in command_str.split(";"):
command = command.strip()
try:
ok &= self.execute(command)
except Exception as err:
print("Command error: %s" % err)
raise
ok = False
if not ok:
break
if ok:
self.previous_command = command_str
except KeyboardInterrupt:
self.interrupt()
except NewProcessEvent as event:
self.newProcess(event)
except ProcessSignal as event:
self.processSignal(event)
except ProcessExit as event:
error(event)
self.nextProcess()
except ProcessExecution as event:
self.processExecution(event)
except PtraceError as err:
error("ERROR: %s" % err)
if err.errno == ESRCH:
self.deleteProcess(err.pid)
return False
def runDebugger(self):
self.setupDebugger()
# Create new process
try:
self.process = self.createProcess()
except ChildError as err:
writeError(getLogger(), err, "Unable to create child process")
return
if not self.process:
return
# Trace syscalls
self.invite = '(gdb) '
self.previous_command = None
while True:
if not self.debugger:
# There is no more process: quit
return
done = self.mainLoop()
if done:
return
def main(self):
self.debugger = PtraceDebugger()
try:
self.runDebugger()
except KeyboardInterrupt:
error("Interrupt debugger: quit!")
except PTRACE_ERRORS as err:
writeError(getLogger(), err, "Debugger error")
self.process = None
self.debugger.quit()
error("Quit gdb.")
self.restoreTerminal()
if __name__ == "__main__":
Gdb().main()
python-ptrace-0.9.3/setup.cfg 0000664 0001750 0001750 00000000046 13160156527 016433 0 ustar haypo haypo 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
python-ptrace-0.9.3/runtests.py 0000775 0001750 0001750 00000021603 13047323111 017045 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
"""Run Tulip unittests.
Usage:
python3 runtests.py [flags] [pattern] ...
Patterns are matched against the fully qualified name of the test,
including package, module, class and method,
e.g. 'tests.test_events.PolicyTests.testPolicy'.
For full help, try --help.
runtests.py --coverage is equivalent of:
$(COVERAGE) run --branch runtests.py -v
$(COVERAGE) html $(list of files)
$(COVERAGE) report -m $(list of files)
"""
# Originally written by Beech Horn (for NDB).
from __future__ import print_function
import optparse
import gc
import logging
import os
import re
import sys
import textwrap
try:
import coverage
except ImportError:
coverage = None
if sys.version_info < (3,):
sys.exc_clear()
try:
import unittest
from unittest.signals import installHandler
except ImportError:
import unittest2 as unittest
from unittest2.signals import installHandler
ARGS = optparse.OptionParser(description="Run all unittests.", usage="%prog")
ARGS.add_option(
'-v', '--verbose', action="store_true", dest='verbose',
default=0, help='verbose')
ARGS.add_option(
'-x', action="store_true", dest='exclude', help='exclude tests')
ARGS.add_option(
'-f', '--failfast', action="store_true", default=False,
dest='failfast', help='Stop on first fail or error')
ARGS.add_option(
'-c', '--catch', action="store_true", default=False,
dest='catchbreak', help='Catch control-C and display results')
ARGS.add_option(
'--forever', action="store_true", dest='forever', default=False,
help='run tests forever to catch sporadic errors')
ARGS.add_option(
'--findleaks', action='store_true', dest='findleaks',
help='detect tests that leak memory')
ARGS.add_option(
'-q', action="store_true", dest='quiet', help='quiet')
ARGS.add_option(
'--tests', action="store", dest='testsdir', default='tests',
help='tests directory')
ARGS.add_option(
'--coverage', action="store_true", dest='coverage',
help='enable html coverage report')
ARGS.add_option(
'--pattern', action="append",
help='optional regex patterns to match test ids (default all tests)')
if sys.version_info >= (3, 3):
import importlib.machinery
def load_module(modname, sourcefile):
loader = importlib.machinery.SourceFileLoader(modname, sourcefile)
return loader.load_module()
else:
import imp
def load_module(modname, sourcefile):
return imp.load_source(modname, sourcefile)
def load_modules(basedir, suffix='.py'):
def list_dir(prefix, dir):
files = []
modpath = os.path.join(dir, '__init__.py')
if os.path.isfile(modpath):
mod = os.path.split(dir)[-1]
files.append(('{0}{1}'.format(prefix, mod), modpath))
prefix = '{0}{1}.'.format(prefix, mod)
for name in os.listdir(dir):
path = os.path.join(dir, name)
if os.path.isdir(path):
files.extend(list_dir('{0}{1}.'.format(prefix, name), path))
else:
if (name != '__init__.py' and
name.endswith(suffix) and
not name.startswith(('.', '_'))):
files.append(('{0}{1}'.format(prefix, name[:-3]), path))
return files
mods = []
for modname, sourcefile in list_dir('', basedir):
if modname == 'runtests':
continue
try:
mod = load_module(modname, sourcefile)
mods.append((mod, sourcefile))
except SyntaxError:
raise
except Exception as err:
print("Skipping '{0}': {1}".format(modname, err), file=sys.stderr)
return mods
class TestsFinder:
def __init__(self, testsdir, includes=(), excludes=()):
self._testsdir = testsdir
self._includes = includes
self._excludes = excludes
self.find_available_tests()
def find_available_tests(self):
"""
Find available test classes without instantiating them.
"""
self._test_factories = []
mods = [mod for mod, _ in load_modules(self._testsdir)]
for mod in mods:
for name in set(dir(mod)):
if 'Test' in name:
self._test_factories.append(getattr(mod, name))
def load_tests(self):
"""
Load test cases from the available test classes and apply
optional include / exclude filters.
"""
loader = unittest.TestLoader()
suite = unittest.TestSuite()
for test_factory in self._test_factories:
tests = loader.loadTestsFromTestCase(test_factory)
if self._includes:
tests = [test
for test in tests
if any(re.search(pat, test.id())
for pat in self._includes)]
if self._excludes:
tests = [test
for test in tests
if not any(re.search(pat, test.id())
for pat in self._excludes)]
suite.addTests(tests)
return suite
class TestResult(unittest.TextTestResult):
def __init__(self, stream, descriptions, verbosity):
super().__init__(stream, descriptions, verbosity)
self.leaks = []
def startTest(self, test):
super().startTest(test)
gc.collect()
def addSuccess(self, test):
super().addSuccess(test)
gc.collect()
if gc.garbage:
if self.showAll:
self.stream.writeln(
" Warning: test created {} uncollectable "
"object(s).".format(len(gc.garbage)))
# move the uncollectable objects somewhere so we don't see
# them again
self.leaks.append((self.getDescription(test), gc.garbage[:]))
del gc.garbage[:]
class TestRunner(unittest.TextTestRunner):
resultclass = TestResult
def run(self, test):
result = super().run(test)
if result.leaks:
self.stream.writeln("{0} tests leaks:".format(len(result.leaks)))
for name, leaks in result.leaks:
self.stream.writeln(' ' * 4 + name + ':')
for leak in leaks:
self.stream.writeln(' ' * 8 + repr(leak))
return result
def runtests():
args, commands = ARGS.parse_args()
if args.coverage and coverage is None:
URL = "bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py"
print(textwrap.dedent("""
coverage package is not installed.
To install coverage3 for Python 3, you need:
- Setuptools (https://pypi.python.org/pypi/setuptools)
What worked for me:
- download {0}
* curl -O https://{0}
- python3 ez_setup.py
- python3 -m easy_install coverage
""".format(URL)).strip())
sys.exit(1)
testsdir = os.path.abspath(args.testsdir)
if not os.path.isdir(testsdir):
print("Tests directory is not found: {0}\n".format(testsdir))
ARGS.print_help()
return
excludes = includes = []
if args.exclude:
excludes = args.pattern
else:
includes = args.pattern
v = 0 if args.quiet else args.verbose + 1
failfast = args.failfast
catchbreak = args.catchbreak
findleaks = args.findleaks
runner_factory = TestRunner if findleaks else unittest.TextTestRunner
if args.coverage:
cov = coverage.coverage(branch=True,
source=['asyncio'],
)
cov.start()
finder = TestsFinder(args.testsdir, includes, excludes)
logger = logging.getLogger()
if v == 0:
logger.setLevel(logging.CRITICAL)
elif v == 1:
logger.setLevel(logging.ERROR)
elif v == 2:
logger.setLevel(logging.WARNING)
elif v == 3:
logger.setLevel(logging.INFO)
elif v >= 4:
logger.setLevel(logging.DEBUG)
if catchbreak:
installHandler()
try:
if args.forever:
while True:
tests = finder.load_tests()
result = runner_factory(verbosity=v,
failfast=failfast).run(tests)
if not result.wasSuccessful():
sys.exit(1)
else:
tests = finder.load_tests()
result = runner_factory(verbosity=v,
failfast=failfast).run(tests)
sys.exit(not result.wasSuccessful())
finally:
if args.coverage:
cov.stop()
cov.save()
cov.html_report(directory='htmlcov')
print("\nCoverage report:")
cov.report(show_missing=False)
here = os.path.dirname(os.path.abspath(__file__))
print("\nFor html report:")
print("open file://{0}/htmlcov/index.html".format(here))
if __name__ == '__main__':
runtests()
python-ptrace-0.9.3/tox.ini 0000664 0001750 0001750 00000000675 13047321200 016117 0 ustar haypo haypo 0000000 0000000 [tox]
envlist = py2, py3, pep8
[testenv]
commands=
python test_doc.py
python runtests.py
[testenv:py2]
basepython = python
[testenv:py3]
basepython = python3
[testenv:pep8]
deps = flake8
commands =
flake8 ptrace/ tests/ gdb.py runtests.py setup_cptrace.py setup.py strace.py SYSCALL_PROTOTYPES.codegen.py test_doc.py
[flake8]
# E501 line too long (88 > 79 characters)
# W503 line break before binary operator
ignore = E501,W503
python-ptrace-0.9.3/ptrace/ 0000775 0001750 0001750 00000000000 13160156527 016070 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/ptrace/version.py 0000664 0001750 0001750 00000000164 13050122242 020111 0 ustar haypo haypo 0000000 0000000 PACKAGE = "python-ptrace"
VERSION = "0.9.3"
WEBSITE = "http://python-ptrace.readthedocs.io/"
LICENSE = "GNU GPL v2"
python-ptrace-0.9.3/ptrace/__init__.py 0000664 0001750 0001750 00000000150 13047323112 020163 0 ustar haypo haypo 0000000 0000000 from ptrace.signames import SIGNAMES, signalName # noqa
from ptrace.error import PtraceError # noqa
python-ptrace-0.9.3/ptrace/profiler.py 0000664 0001750 0001750 00000001715 13047323111 020255 0 ustar haypo haypo 0000000 0000000 from hotshot import Profile
from hotshot.stats import load as loadStats
from os import unlink
from io import StringIO
def runProfiler(logger, func, args=tuple(), kw={},
verbose=True, nb_func=25,
sort_by=('time',)):
"""
Run a function in a profiler and then display the functions sorted by time.
"""
profile_filename = "/tmp/profiler"
prof = Profile(profile_filename)
try:
logger.warning("Run profiler")
result = prof.runcall(func, *args, **kw)
prof.close()
logger.error("Profiler: Process data...")
stat = loadStats(profile_filename)
stat.strip_dirs()
stat.sort_stats(*sort_by)
logger.error("Profiler: Result:")
log = StringIO()
stat.stream = log
stat.print_stats(nb_func)
log.seek(0)
for line in log:
logger.error(line.rstrip())
return result
finally:
unlink(profile_filename)
python-ptrace-0.9.3/ptrace/func_arg.py 0000664 0001750 0001750 00000007027 13047323112 020222 0 ustar haypo haypo 0000000 0000000 from ptrace.error import PTRACE_ERRORS, writeError
from logging import getLogger
from ptrace.ctypes_tools import formatAddress
class FunctionArgument(object):
"""
Description of a function argument. Attributes:
- function: a Function object
- index (int): index of the argument (starting at zero)
- options: a FunctionCallOptions object
- value (int)
- type (str, optional)
- text (str): string describing the argument
Don't use text attribute directly, use getText() to format the
argument instead.
"""
def __init__(self, function, index, options,
value=None, type=None, name=None):
self.function = function
self.index = index
self.options = options
self.value = value
self.type = type
self.name = name
self.text = None
def getText(self):
if not self.text:
try:
text = self.createText()
if text is not None:
self.text = str(text)
elif self.type and self.type.endswith("*"):
self.text = formatAddress(self.value)
else:
self.text = repr(self.value)
except PTRACE_ERRORS as err:
writeError(getLogger(), err,
"Format argument %s of function %s() value error"
% (self.name, self.function.name))
self.text = repr(self.value)
return self.text
def format(self):
text = self.getText()
options = self.options
if options.write_argname and self.name:
if options.write_types and self.type:
return "%s %s=%s" % (self.type, self.name, text)
else:
return "%s=%s" % (self.name, text)
elif options.write_types and self.type:
return "(%s)%s" % (self.type, text)
else:
return text
def createText(self):
return repr(self.value)
def formatPointer(self, value, address):
if self.options.write_address:
return "%s at %s" % (value, formatAddress(address))
else:
return value
def readStruct(self, address, struct):
address = self.value
struct_name = struct.__name__
data = self.function.process.readStruct(address, struct)
arguments = []
for name, argtype in struct._fields_:
value = getattr(data, name)
try:
text = self.formatStructValue(struct_name, name, value)
if text is not None:
text = str(text)
else:
text = repr(value)
except PTRACE_ERRORS as err:
writeError(getLogger(), err, "Format struct value error")
text = repr(value)
arguments.append("%s=%s" % (name, text))
data = "<%s %s>" % (struct_name, ", ".join(arguments))
return self.formatPointer(data, address)
def formatStructValue(self, struct, name, value):
return None
def readArray(self, address, basetype, count):
array = self.function.process.readArray(address, basetype, count)
arguments = []
for index in range(count):
value = array[index]
value = str(value)
arguments.append(value)
arguments = ", ".join(arguments)
return self.formatPointer("<(%s)>" % arguments, address)
def __repr__(self):
return "argument %s of %s()" % (self.name, self.function.name)
python-ptrace-0.9.3/ptrace/ctypes_libc.py 0000664 0001750 0001750 00000000377 13047323113 020740 0 ustar haypo haypo 0000000 0000000 """
Load the system C library. Variables:
- LIBC_FILENAME: the C library filename
- libc: the loaded library
"""
from ctypes import CDLL
from ctypes.util import find_library
LIBC_FILENAME = find_library('c')
libc = CDLL(LIBC_FILENAME, use_errno=True)
python-ptrace-0.9.3/ptrace/os_tools.py 0000664 0001750 0001750 00000001452 13047323111 020272 0 ustar haypo haypo 0000000 0000000 """
Constants about the operating system:
- RUNNING_PYPY (bool)
- RUNNING_WINDOWS (bool)
- RUNNING_LINUX (bool)
- RUNNING_FREEBSD (bool)
- RUNNING_OPENBSD (bool)
- RUNNING_MACOSX (bool)
- RUNNING_BSD (bool)
- HAS_PROC (bool)
- HAS_PTRACE (bool)
"""
from sys import platform, version, version_info
RUNNING_PYTHON3 = version_info[0] == 3
RUNNING_PYPY = ("pypy" in version.lower())
RUNNING_WINDOWS = (platform == 'win32')
RUNNING_LINUX = platform.startswith('linux')
RUNNING_FREEBSD = (platform.startswith('freebsd')
or platform.startswith('gnukfreebsd'))
RUNNING_OPENBSD = platform.startswith('openbsd')
RUNNING_MACOSX = (platform == 'darwin')
RUNNING_BSD = RUNNING_FREEBSD or RUNNING_MACOSX or RUNNING_OPENBSD
HAS_PROC = RUNNING_LINUX
HAS_PTRACE = (RUNNING_BSD or RUNNING_LINUX)
python-ptrace-0.9.3/ptrace/tools.py 0000664 0001750 0001750 00000010070 13047323324 017573 0 ustar haypo haypo 0000000 0000000 from ctypes import sizeof
from ptrace.ctypes_tools import formatUintHex16, formatUintHex32, formatWordHex
from datetime import datetime, timedelta
from os import getenv, access, X_OK, pathsep, getcwd
from os.path import join as path_join, isabs, dirname, normpath
def dumpRegs(log, regs):
"""
Dump all registers using log callback (write one line).
"""
width = max(len(name) for name, type in regs._fields_)
name_format = "%% %us" % width
for name, type in regs._fields_:
value = getattr(regs, name)
name = name_format % name
if sizeof(type) == 32:
value = formatUintHex32(value)
elif sizeof(type) == 16:
value = formatUintHex16(value)
else:
value = formatWordHex(value)
log("%s = %s" % (name, value))
def readBits(value, bitmasks):
"""
Extract bits from the integer value using a list of bit masks.
bitmasks is a list of tuple (mask, text).
>>> bitmask = (
... (1, "exec"),
... (2, "write"),
... (4, "read"))
...
>>> readBits(5, bitmask)
['exec', 'read']
>>> readBits(12, bitmask)
['read', '8']
"""
bitset = []
for mask, item in bitmasks:
if not value & mask:
continue
bitset.append(item)
value = value & ~mask
if value:
bitset.append(str(value))
return bitset
def formatBits(value, bitmasks, empty_text=None, format_value=str):
"""
Format a value using a bitmask: see readBits() functions.
>>> bitmask = (
... (1, "exec"),
... (2, "write"),
... (4, "read"))
...
>>> formatBits(5, bitmask, empty_text="no permission")
' (5)'
>>> formatBits(0, bitmask, empty_text="no permission")
'no permission'
"""
orig_value = value
text = readBits(value, bitmasks)
if text:
text = "%s" % ("|".join(text))
if value:
text = "<%s> (%s)" % (text, format_value(orig_value))
return text
else:
if empty_text:
return empty_text
else:
return str(value)
LOCAL_TIMEZONE_OFFSET = datetime.fromtimestamp(
0) - datetime.utcfromtimestamp(0)
# Start of UNIX timestamp (Epoch): 1st January 1970 at 00:00
UNIX_TIMESTAMP_T0 = datetime(1970, 1, 1)
def timestampUNIX(value, is_local):
"""
Convert an UNIX (32-bit) timestamp to datetime object. Timestamp value
is the number of seconds since the 1st January 1970 at 00:00. Maximum
value is 2147483647: 19 january 2038 at 03:14:07.
May raise ValueError for invalid value: value have to be in 0..2147483647.
>>> timestampUNIX(0, False)
datetime.datetime(1970, 1, 1, 0, 0)
>>> timestampUNIX(1154175644.37, False)
datetime.datetime(2006, 7, 29, 12, 20, 44, 370000)
"""
timestamp = UNIX_TIMESTAMP_T0 + timedelta(seconds=value)
if is_local:
timestamp += LOCAL_TIMEZONE_OFFSET
return timestamp
def locateProgram(program):
"""
Locate a program using the PATH environment variable. Return the
unchanged program value if it's not possible to get the full
program path.
"""
if isabs(program):
return program
if dirname(program):
# ./test => $PWD/./test
# ../python => $PWD/../python
program = path_join(getcwd(), program)
program = normpath(program)
return program
paths = getenv('PATH')
if not paths:
return program
for path in paths.split(pathsep):
filename = path_join(path, program)
if access(filename, X_OK):
return filename
return program
def minmax(min_value, value, max_value):
"""
Restrict value to [min_value; max_value]
>>> minmax(-2, -3, 10)
-2
>>> minmax(-2, 27, 10)
10
>>> minmax(-2, 0, 10)
0
"""
return min(max(min_value, value), max_value)
def inverseDict(data):
"""
Inverse a dictionary.
>>> inverseDict({"0x10": 16, "0x20": 32}) == {32: '0x20', 16: '0x10'}
True
"""
result = {}
for key, value in data.items():
result[value] = key
return result
python-ptrace-0.9.3/ptrace/terminal.py 0000664 0001750 0001750 00000001606 13047323113 020247 0 ustar haypo haypo 0000000 0000000 """
Terminal functions.
"""
from termios import tcgetattr, tcsetattr, ECHO, TCSADRAIN, TIOCGWINSZ
from sys import stdin, stdout
from fcntl import ioctl
from struct import unpack
import os
TERMIO_LFLAGS = 3
def _terminalSize():
fd = stdout.fileno()
size = ioctl(fd, TIOCGWINSZ, '1234')
height, width = unpack('hh', size)
return (width, height)
def terminalWidth():
"""
Get the terminal width in characters.
"""
return _terminalSize()[0]
def enableEchoMode():
"""
Enable echo mode in the terminal. Return True if the echo mode is set
correctly, or False if the mode was already set.
"""
fd = stdin.fileno()
if not os.isatty(fd):
return False
state = tcgetattr(fd)
if state[TERMIO_LFLAGS] & ECHO:
return False
state[TERMIO_LFLAGS] = state[TERMIO_LFLAGS] | ECHO
tcsetattr(fd, TCSADRAIN, state)
return True
python-ptrace-0.9.3/ptrace/syscall/ 0000775 0001750 0001750 00000000000 13160156527 017542 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/ptrace/syscall/prototypes.py 0000664 0001750 0001750 00000132002 13047323112 022330 0 ustar haypo haypo 0000000 0000000 # From Linux kernel source code
# include/linux/syscalls.h
# arch/i386/kernel/syscall_table.S
# arch/um/include/sysdep-i386/syscalls.h
# arch/um/sys-i386/sys_call_table.S
ALIASES = {
"brk": ("break",),
"fadvise64": ("posix_fadvise",),
"fstatat64": ("fstatat",),
"getcwd": ("__getcwd",),
"mmap_pgoff": ("mmap", "mmap2",),
"pread64": ("pread",),
"prlimit64": ("prlimit",),
"pselect6": ("pselect",),
"pwrite64": ("pwrite",),
}
# Name of arguments containing a filename or a path
FILENAME_ARGUMENTS = set(
("filename", "pathname", "path", "oldname", "newname", "old", "new"))
DIRFD_ARGUMENTS = set(("dirfd", "olddirfd", "newdirfd"))
SYSCALL_PROTOTYPES = {
"accept": ("long", (
("int", "sockfd"),
("struct sockaddr *", "addr"),
("int *", "addrlen"),
)),
"accept4": ("long", (
("int", "sockfd"),
("struct sockaddr *", "addr"),
("int *", "addrlen"),
("int", "flags"),
)),
"access": ("long", (
("const char *", "filename"),
("int", "mode"),
)),
"acct": ("long", (
("const char *", "name"),
)),
"add_key": ("long", (
("const char *", "_type"),
("const char *", "_description"),
("const void *", "_payload"),
("size_t", "plen"),
("key_serial_t", "destringid"),
)),
"adjtimex": ("long", (
("struct timex *", "txc_p"),
)),
"alarm": ("long", (
("unsigned int", "seconds"),
)),
"bdflush": ("long", (
("int", "func"),
("long", "data"),
)),
"bind": ("long", (
("int", "sockfd"),
("struct sockaddr *", "addr"),
("int", "addrlen"),
)),
"bpf": ("long", (
("int", "cmd"),
("union bpf_attr *", "attr"),
("unsigned int", "size"),
)),
"brk": ("long", (
("unsigned long", "brk"),
)),
"capget": ("long", (
("cap_user_header_t", "header"),
("cap_user_data_t", "dataptr"),
)),
"capset": ("long", (
("cap_user_header_t", "header"),
("const cap_user_data_t", "data"),
)),
"chdir": ("long", (
("const char *", "filename"),
)),
"chmod": ("long", (
("const char *", "filename"),
("umode_t", "mode"),
)),
"chown": ("long", (
("const char *", "filename"),
("uid_t", "user"),
("gid_t", "group"),
)),
"chown16": ("long", (
("const char *", "filename"),
("old_uid_t", "user"),
("old_gid_t", "group"),
)),
"chroot": ("long", (
("const char *", "filename"),
)),
"clock_adjtime": ("long", (
("clockid_t", "which_clock"),
("struct timex *", "tx"),
)),
"clock_getres": ("long", (
("clockid_t", "which_clock"),
("struct timespec *", "tp"),
)),
"clock_gettime": ("long", (
("clockid_t", "which_clock"),
("struct timespec *", "tp"),
)),
"clock_nanosleep": ("long", (
("clockid_t", "which_clock"),
("int", "flags"),
("const struct timespec *", "rqtp"),
("struct timespec *", "rmtp"),
)),
"clock_settime": ("long", (
("clockid_t", "which_clock"),
("const struct timespec *", "tp"),
)),
"clone": ("long", (
("unsigned long", "flags"),
("unsigned long", "child_stack"),
("int *", "ptid"),
("int *", "ctid"),
("unsigned long", "regs"),
)),
"close": ("long", (
("unsigned int", "fd"),
)),
"connect": ("long", (
("int", "sockfd"),
("struct sockaddr *", "addr"),
("int", "addrlen"),
)),
"copy_file_range": ("long", (
("int", "fd_in"),
("loff_t *", "off_in"),
("int", "fd_out"),
("loff_t *", "off_out"),
("size_t", "len"),
("unsigned int", "flags"),
)),
"creat": ("long", (
("const char *", "pathname"),
("umode_t", "mode"),
)),
"delete_module": ("long", (
("const char *", "name_user"),
("unsigned int", "flags"),
)),
"dup": ("long", (
("unsigned int", "fildes"),
)),
"dup2": ("long", (
("unsigned int", "oldfd"),
("unsigned int", "newfd"),
)),
"dup3": ("long", (
("unsigned int", "oldfd"),
("unsigned int", "newfd"),
("int", "flags"),
)),
"epoll_create": ("long", (
("int", "size"),
)),
"epoll_create1": ("long", (
("int", "flags"),
)),
"epoll_ctl": ("long", (
("int", "epfd"),
("int", "op"),
("int", "fd"),
("struct epoll_event *", "event"),
)),
"epoll_pwait": ("long", (
("int", "epfd"),
("struct epoll_event *", "events"),
("int", "maxevents"),
("int", "timeout"),
("const sigset_t *", "sigmask"),
("size_t", "sigsetsize"),
)),
"epoll_wait": ("long", (
("int", "epfd"),
("struct epoll_event *", "events"),
("int", "maxevents"),
("int", "timeout"),
)),
"eventfd": ("long", (
("unsigned int", "count"),
)),
"eventfd2": ("long", (
("unsigned int", "count"),
("int", "flags"),
)),
"execve": ("long", (
("const char *", "filename"),
("const char *const *", "argv"),
("const char *const *", "envp"),
)),
"execveat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("const char *const *", "argv"),
("const char *const *", "envp"),
("int", "flags"),
)),
"exit": ("long", (
("int", "error_code"),
)),
"exit_group": ("long", (
("int", "error_code"),
)),
"faccessat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("int", "mode"),
)),
"fadvise64": ("long", (
("int", "fd"),
("loff_t", "offset"),
("size_t", "len"),
("int", "advice"),
)),
"fadvise64_64": ("long", (
("int", "fd"),
("loff_t", "offset"),
("loff_t", "len"),
("int", "advice"),
)),
"fallocate": ("long", (
("int", "fd"),
("int", "mode"),
("loff_t", "offset"),
("loff_t", "len"),
)),
"fanotify_init": ("long", (
("unsigned int", "flags"),
("unsigned int", "event_f_flags"),
)),
"fanotify_mark": ("long", (
("int", "fanotify_fd"),
("unsigned int", "flags"),
("u64", "mask"),
("int", "fd"),
("const char *", "pathname"),
)),
"fchdir": ("long", (
("unsigned int", "fd"),
)),
"fchmod": ("long", (
("unsigned int", "fd"),
("umode_t", "mode"),
)),
"fchmodat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("umode_t", "mode"),
)),
"fchown": ("long", (
("unsigned int", "fd"),
("uid_t", "user"),
("gid_t", "group"),
)),
"fchown16": ("long", (
("unsigned int", "fd"),
("old_uid_t", "user"),
("old_gid_t", "group"),
)),
"fchownat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("uid_t", "user"),
("gid_t", "group"),
("int", "flag"),
)),
"fcntl": ("long", (
("unsigned int", "fd"),
("unsigned int", "cmd"),
("unsigned long", "arg"),
)),
"fcntl64": ("long", (
("unsigned int", "fd"),
("unsigned int", "cmd"),
("unsigned long", "arg"),
)),
"fdatasync": ("long", (
("unsigned int", "fd"),
)),
"fgetxattr": ("long", (
("int", "fd"),
("const char *", "name"),
("void *", "value"),
("size_t", "size"),
)),
"finit_module": ("long", (
("int", "fd"),
("const char *", "uargs"),
("int", "flags"),
)),
"flistxattr": ("long", (
("int", "fd"),
("char *", "list"),
("size_t", "size"),
)),
"flock": ("long", (
("unsigned int", "fd"),
("unsigned int", "cmd"),
)),
"fork": ("long", (
)),
"fremovexattr": ("long", (
("int", "fd"),
("const char *", "name"),
)),
"fsetxattr": ("long", (
("int", "fd"),
("const char *", "name"),
("const void *", "value"),
("size_t", "size"),
("int", "flags"),
)),
"fstat": ("long", (
("unsigned int", "fd"),
("struct __old_kernel_stat *", "statbuf"),
)),
"fstat64": ("long", (
("unsigned long", "fd"),
("struct stat64 *", "statbuf"),
)),
"fstatat64": ("long", (
("int", "dfd"),
("const char *", "filename"),
("struct stat64 *", "statbuf"),
("int", "flag"),
)),
"fstatfs": ("long", (
("unsigned int", "fd"),
("struct statfs *", "buf"),
)),
"fstatfs64": ("long", (
("unsigned int", "fd"),
("size_t", "sz"),
("struct statfs64 *", "buf"),
)),
"fsync": ("long", (
("unsigned int", "fd"),
)),
"ftruncate": ("long", (
("unsigned int", "fd"),
("unsigned long", "length"),
)),
"ftruncate64": ("long", (
("unsigned int", "fd"),
("loff_t", "length"),
)),
"futex": ("long", (
("u32 *", "uaddr"),
("int", "op"),
("u32", "val"),
("struct timespec *", "utime"),
("u32 *", "uaddr2"),
("u32", "val3"),
)),
"futimesat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("struct timeval *", "utimes"),
)),
"get_mempolicy": ("long", (
("int *", "policy"),
("unsigned long *", "nmask"),
("unsigned long", "maxnode"),
("unsigned long", "addr"),
("unsigned long", "flags"),
)),
"get_robust_list": ("long", (
("int", "pid"),
("struct robust_list_head * *", "head_ptr"),
("size_t *", "len_ptr"),
)),
"getcpu": ("long", (
("unsigned *", "cpu"),
("unsigned *", "node"),
("struct getcpu_cache *", "cache"),
)),
"getcwd": ("long", (
("char *", "pathname"),
("unsigned long", "size"),
)),
"getdents": ("long", (
("unsigned int", "fd"),
("struct linux_dirent *", "dirent"),
("unsigned int", "count"),
)),
"getdents64": ("long", (
("unsigned int", "fd"),
("struct linux_dirent64 *", "dirent"),
("unsigned int", "count"),
)),
"getegid": ("long", (
)),
"getegid16": ("long", (
)),
"geteuid": ("long", (
)),
"geteuid16": ("long", (
)),
"getgid": ("long", (
)),
"getgid16": ("long", (
)),
"getgroups": ("long", (
("int", "gidsetsize"),
("gid_t *", "grouplist"),
)),
"getgroups16": ("long", (
("int", "gidsetsize"),
("old_gid_t *", "grouplist"),
)),
"gethostname": ("long", (
("char *", "name"),
("int", "len"),
)),
"getitimer": ("long", (
("int", "which"),
("struct itimerval *", "value"),
)),
"getpeername": ("long", (
("int", "sockfd"),
("struct sockaddr *", "addr"),
("int *", "addrlen"),
)),
"getpgid": ("long", (
("pid_t", "pid"),
)),
"getpgrp": ("long", (
)),
"getpid": ("long", (
)),
"getppid": ("long", (
)),
"getpriority": ("long", (
("int", "which"),
("int", "who"),
)),
"getrandom": ("long", (
("char *", "buf"),
("size_t", "count"),
("unsigned int", "flags"),
)),
"getresgid": ("long", (
("gid_t *", "rgid"),
("gid_t *", "egid"),
("gid_t *", "sgid"),
)),
"getresgid16": ("long", (
("old_gid_t *", "rgid"),
("old_gid_t *", "egid"),
("old_gid_t *", "sgid"),
)),
"getresuid": ("long", (
("uid_t *", "ruid"),
("uid_t *", "euid"),
("uid_t *", "suid"),
)),
"getresuid16": ("long", (
("old_uid_t *", "ruid"),
("old_uid_t *", "euid"),
("old_uid_t *", "suid"),
)),
"getrlimit": ("long", (
("unsigned int", "resource"),
("struct rlimit *", "rlim"),
)),
"getrusage": ("long", (
("int", "who"),
("struct rusage *", "ru"),
)),
"getsid": ("long", (
("pid_t", "pid"),
)),
"getsockname": ("long", (
("int", "sockfd"),
("struct sockaddr *", "addr"),
("int *", "addrlen"),
)),
"getsockopt": ("long", (
("int", "fd"),
("int", "level"),
("int", "optname"),
("char *", "optval"),
("int *", "optlen"),
)),
"gettid": ("long", (
)),
"gettimeofday": ("long", (
("struct timeval *", "tv"),
("struct timezone *", "tz"),
)),
"getuid": ("long", (
)),
"getuid16": ("long", (
)),
"getxattr": ("long", (
("const char *", "path"),
("const char *", "name"),
("void *", "value"),
("size_t", "size"),
)),
"init_module": ("long", (
("void *", "umod"),
("unsigned long", "len"),
("const char *", "uargs"),
)),
"inotify_add_watch": ("long", (
("int", "fd"),
("const char *", "path"),
("u32", "mask"),
)),
"inotify_init": ("long", (
)),
"inotify_init1": ("long", (
("int", "flags"),
)),
"inotify_rm_watch": ("long", (
("int", "fd"),
("__s32", "wd"),
)),
"io_cancel": ("long", (
("aio_context_t", "ctx_id"),
("struct iocb *", "iocb"),
("struct io_event *", "result"),
)),
"io_destroy": ("long", (
("aio_context_t", "ctx"),
)),
"io_getevents": ("long", (
("aio_context_t", "ctx_id"),
("long", "min_nr"),
("long", "nr"),
("struct io_event *", "events"),
("struct timespec *", "timeout"),
)),
"io_setup": ("long", (
("unsigned", "nr_reqs"),
("aio_context_t *", "ctx"),
)),
"io_submit": ("long", (
("aio_context_t", "ctx_id"),
("long", "nr"),
("struct iocb * *", "iocbpp"),
)),
"ioctl": ("long", (
("unsigned int", "fd"),
("unsigned int", "cmd"),
("unsigned long", "arg"),
)),
"ioperm": ("long", (
("unsigned long", "from"),
("unsigned long", "num"),
("int", "on"),
)),
"ioprio_get": ("long", (
("int", "which"),
("int", "who"),
)),
"ioprio_set": ("long", (
("int", "which"),
("int", "who"),
("int", "ioprio"),
)),
"ipc": ("long", (
("unsigned int", "call"),
("int", "first"),
("unsigned long", "second"),
("unsigned long", "third"),
("void *", "ptr"),
("long", "fifth"),
)),
"kcmp": ("long", (
("pid_t", "pid1"),
("pid_t", "pid2"),
("int", "type"),
("unsigned long", "idx1"),
("unsigned long", "idx2"),
)),
"kexec_file_load": ("long", (
("int", "kernel_fd"),
("int", "initrd_fd"),
("unsigned long", "cmdline_len"),
("const char *", "cmdline_ptr"),
("unsigned long", "flags"),
)),
"kexec_load": ("long", (
("unsigned long", "entry"),
("unsigned long", "nr_segments"),
("struct kexec_segment *", "segments"),
("unsigned long", "flags"),
)),
"keyctl": ("long", (
("int", "cmd"),
("unsigned long", "arg2"),
("unsigned long", "arg3"),
("unsigned long", "arg4"),
("unsigned long", "arg5"),
)),
"kill": ("long", (
("int", "pid"),
("int", "sig"),
)),
"lchown": ("long", (
("const char *", "filename"),
("uid_t", "user"),
("gid_t", "group"),
)),
"lchown16": ("long", (
("const char *", "filename"),
("old_uid_t", "user"),
("old_gid_t", "group"),
)),
"lgetxattr": ("long", (
("const char *", "path"),
("const char *", "name"),
("void *", "value"),
("size_t", "size"),
)),
"link": ("long", (
("const char *", "oldname"),
("const char *", "newname"),
)),
"linkat": ("long", (
("int", "olddfd"),
("const char *", "oldname"),
("int", "newdfd"),
("const char *", "newname"),
("int", "flags"),
)),
"listen": ("long", (
("int", "sockfd"),
("int", "backlog"),
)),
"listxattr": ("long", (
("const char *", "path"),
("char *", "list"),
("size_t", "size"),
)),
"llistxattr": ("long", (
("const char *", "path"),
("char *", "list"),
("size_t", "size"),
)),
"llseek": ("long", (
("unsigned int", "fd"),
("unsigned long", "offset_high"),
("unsigned long", "offset_low"),
("loff_t *", "result"),
("unsigned int", "whence"),
)),
"lookup_dcookie": ("long", (
("u64", "cookie64"),
("char *", "buf"),
("size_t", "len"),
)),
"lremovexattr": ("long", (
("const char *", "path"),
("const char *", "name"),
)),
"lseek": ("long", (
("unsigned int", "fd"),
("off_t", "offset"),
("unsigned int", "whence"),
)),
"lsetxattr": ("long", (
("const char *", "path"),
("const char *", "name"),
("const void *", "value"),
("size_t", "size"),
("int", "flags"),
)),
"lstat": ("long", (
("const char *", "filename"),
("struct __old_kernel_stat *", "statbuf"),
)),
"lstat64": ("long", (
("const char *", "filename"),
("struct stat64 *", "statbuf"),
)),
"madvise": ("long", (
("unsigned long", "start"),
("size_t", "len"),
("int", "behavior"),
)),
"mbind": ("long", (
("unsigned long", "start"),
("unsigned long", "len"),
("unsigned long", "mode"),
("const unsigned long *", "nmask"),
("unsigned long", "maxnode"),
("unsigned", "flags"),
)),
"membarrier": ("long", (
("int", "cmd"),
("int", "flags"),
)),
"memfd_create": ("long", (
("const char *", "uname_ptr"),
("unsigned int", "flags"),
)),
"migrate_pages": ("long", (
("pid_t", "pid"),
("unsigned long", "maxnode"),
("const unsigned long *", "from"),
("const unsigned long *", "to"),
)),
"mincore": ("long", (
("unsigned long", "start"),
("size_t", "len"),
("unsigned char *", "vec"),
)),
"mkdir": ("long", (
("const char *", "pathname"),
("umode_t", "mode"),
)),
"mkdirat": ("long", (
("int", "dfd"),
("const char *", "pathname"),
("umode_t", "mode"),
)),
"mknod": ("long", (
("const char *", "filename"),
("umode_t", "mode"),
("unsigned", "dev"),
)),
"mknodat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("umode_t", "mode"),
("unsigned", "dev"),
)),
"mlock": ("long", (
("unsigned long", "start"),
("size_t", "len"),
)),
"mlock2": ("long", (
("unsigned long", "start"),
("size_t", "len"),
("int", "flags"),
)),
"mlockall": ("long", (
("int", "flags"),
)),
"mmap_pgoff": ("long", (
("unsigned long", "addr"),
("unsigned long", "len"),
("unsigned long", "prot"),
("unsigned long", "flags"),
("unsigned long", "fd"),
("unsigned long", "pgoff"),
)),
"mount": ("long", (
("char *", "dev_name"),
("char *", "dir_name"),
("char *", "type"),
("unsigned long", "flags"),
("void *", "data"),
)),
"move_pages": ("long", (
("pid_t", "pid"),
("unsigned long", "nr_pages"),
("const void * *", "pages"),
("const int *", "nodes"),
("int *", "status"),
("int", "flags"),
)),
"mprotect": ("long", (
("unsigned long", "start"),
("size_t", "len"),
("unsigned long", "prot"),
)),
"mq_getsetattr": ("long", (
("mqd_t", "mqdes"),
("const struct mq_attr *", "mqstat"),
("struct mq_attr *", "omqstat"),
)),
"mq_notify": ("long", (
("mqd_t", "mqdes"),
("const struct sigevent *", "notification"),
)),
"mq_open": ("long", (
("const char *", "name"),
("int", "oflag"),
("umode_t", "mode"),
("struct mq_attr *", "attr"),
)),
"mq_timedreceive": ("long", (
("mqd_t", "mqdes"),
("char *", "msg_ptr"),
("size_t", "msg_len"),
("unsigned int *", "msg_prio"),
("const struct timespec *", "abs_timeout"),
)),
"mq_timedsend": ("long", (
("mqd_t", "mqdes"),
("const char *", "msg_ptr"),
("size_t", "msg_len"),
("unsigned int", "msg_prio"),
("const struct timespec *", "abs_timeout"),
)),
"mq_unlink": ("long", (
("const char *", "name"),
)),
"mremap": ("long", (
("unsigned long", "addr"),
("unsigned long", "old_len"),
("unsigned long", "new_len"),
("unsigned long", "flags"),
("unsigned long", "new_addr"),
)),
"msgctl": ("long", (
("int", "msqid"),
("int", "cmd"),
("struct msqid_ds *", "buf"),
)),
"msgget": ("long", (
("key_t", "key"),
("int", "msgflg"),
)),
"msgrcv": ("long", (
("int", "msqid"),
("struct msgbuf *", "msgp"),
("size_t", "msgsz"),
("long", "msgtyp"),
("int", "msgflg"),
)),
"msgsnd": ("long", (
("int", "msqid"),
("struct msgbuf *", "msgp"),
("size_t", "msgsz"),
("int", "msgflg"),
)),
"msync": ("long", (
("unsigned long", "start"),
("size_t", "len"),
("int", "flags"),
)),
"munlock": ("long", (
("unsigned long", "start"),
("size_t", "len"),
)),
"munlockall": ("long", (
)),
"munmap": ("long", (
("unsigned long", "addr"),
("size_t", "len"),
)),
"name_to_handle_at": ("long", (
("int", "dfd"),
("const char *", "name"),
("struct file_handle *", "handle"),
("int *", "mnt_id"),
("int", "flag"),
)),
"nanosleep": ("long", (
("struct timespec *", "rqtp"),
("struct timespec *", "rmtp"),
)),
"newfstat": ("long", (
("unsigned int", "fd"),
("struct stat *", "statbuf"),
)),
"newfstatat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("struct stat *", "statbuf"),
("int", "flag"),
)),
"newlstat": ("long", (
("const char *", "filename"),
("struct stat *", "statbuf"),
)),
"newstat": ("long", (
("const char *", "filename"),
("struct stat *", "statbuf"),
)),
"newuname": ("long", (
("struct new_utsname *", "name"),
)),
"ni_syscall": ("long", (
)),
"nice": ("long", (
("int", "increment"),
)),
"old_getrlimit": ("long", (
("unsigned int", "resource"),
("struct rlimit *", "rlim"),
)),
"old_mmap": ("long", (
("struct mmap_arg_struct *", "arg"),
)),
"old_readdir": ("long", (
("unsigned int", "fd"),
("struct old_linux_dirent *", "dirp"),
("unsigned int", "count"),
)),
"old_select": ("long", (
("struct sel_arg_struct *", "arg"),
)),
"oldumount": ("long", (
("char *", "name"),
)),
"olduname": ("long", (
("struct oldold_utsname *", "buf"),
)),
"open": ("long", (
("const char *", "filename"),
("int", "flags"),
("umode_t", "mode"),
)),
"open_by_handle_at": ("long", (
("int", "mountdirfd"),
("struct file_handle *", "handle"),
("int", "flags"),
)),
"openat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("int", "flags"),
("umode_t", "mode"),
)),
"pause": ("long", (
)),
"pciconfig_iobase": ("long", (
("long", "which"),
("unsigned long", "bus"),
("unsigned long", "devfn"),
)),
"pciconfig_read": ("long", (
("unsigned long", "bus"),
("unsigned long", "dfn"),
("unsigned long", "off"),
("unsigned long", "len"),
("void *", "buf"),
)),
"pciconfig_write": ("long", (
("unsigned long", "bus"),
("unsigned long", "dfn"),
("unsigned long", "off"),
("unsigned long", "len"),
("void *", "buf"),
)),
"perf_event_open": ("long", (
("struct perf_event_attr *", "attr_uptr"),
("pid_t", "pid"),
("int", "cpu"),
("int", "group_fd"),
("unsigned long", "flags"),
)),
"personality": ("long", (
("unsigned int", "personality"),
)),
"pipe": ("long", (
("int *", "fildes"),
)),
"pipe2": ("long", (
("int *", "fildes"),
("int", "flags"),
)),
"pivot_root": ("long", (
("const char *", "new_root"),
("const char *", "put_old"),
)),
"poll": ("long", (
("struct pollfd *", "ufds"),
("unsigned int", "nfds"),
("int", "timeout"),
)),
"ppoll": ("long", (
("struct pollfd *", "fds"),
("unsigned int", "nfds"),
("struct timespec *", "tmo_p"),
("const sigset_t *", "sigmask"),
("size_t", ""),
)),
"prctl": ("long", (
("int", "option"),
("unsigned long", "arg2"),
("unsigned long", "arg3"),
("unsigned long", "arg4"),
("unsigned long", "arg5"),
)),
"pread64": ("long", (
("unsigned int", "fd"),
("char *", "buf"),
("size_t", "count"),
("loff_t", "pos"),
)),
"preadv": ("long", (
("unsigned long", "fd"),
("const struct iovec *", "vec"),
("unsigned long", "vlen"),
("unsigned long", "pos_l"),
("unsigned long", "pos_h"),
)),
"prlimit64": ("long", (
("pid_t", "pid"),
("unsigned int", "resource"),
("const struct rlimit64 *", "new_rlim"),
("struct rlimit64 *", "old_rlim"),
)),
"process_vm_readv": ("long", (
("pid_t", "pid"),
("const struct iovec *", "lvec"),
("unsigned long", "liovcnt"),
("const struct iovec *", "rvec"),
("unsigned long", "riovcnt"),
("unsigned long", "flags"),
)),
"process_vm_writev": ("long", (
("pid_t", "pid"),
("const struct iovec *", "lvec"),
("unsigned long", "liovcnt"),
("const struct iovec *", "rvec"),
("unsigned long", "riovcnt"),
("unsigned long", "flags"),
)),
"pselect6": ("long", (
("int", "nfds"),
("fd_set *", "readfds"),
("fd_set *", "writefds"),
("fd_set *", "exceptfds"),
("struct timespec *", "timeout"),
("void *", "sigmask"),
)),
"ptrace": ("long", (
("long", "request"),
("long", "pid"),
("unsigned long", "addr"),
("unsigned long", "data"),
)),
"pwrite64": ("long", (
("unsigned int", "fd"),
("const char *", "buf"),
("size_t", "count"),
("loff_t", "pos"),
)),
"pwritev": ("long", (
("unsigned long", "fd"),
("const struct iovec *", "vec"),
("unsigned long", "vlen"),
("unsigned long", "pos_l"),
("unsigned long", "pos_h"),
)),
"quotactl": ("long", (
("unsigned int", "cmd"),
("const char *", "special"),
("qid_t", "id"),
("void *", "addr"),
)),
"read": ("long", (
("unsigned int", "fd"),
("char *", "buf"),
("size_t", "count"),
)),
"readahead": ("long", (
("int", "fd"),
("loff_t", "offset"),
("size_t", "count"),
)),
"readlink": ("long", (
("const char *", "path"),
("char *", "buf"),
("int", "bufsiz"),
)),
"readlinkat": ("long", (
("int", "dfd"),
("const char *", "path"),
("char *", "buf"),
("int", "bufsiz"),
)),
"readv": ("long", (
("unsigned long", "fd"),
("const struct iovec *", "vec"),
("unsigned long", "vlen"),
)),
"reboot": ("long", (
("int", "magic1"),
("int", "magic2"),
("unsigned int", "cmd"),
("void *", "arg"),
)),
"recv": ("long", (
("int", "sockfd"),
("void *", "buf"),
("size_t", "len"),
("unsigned", "flags"),
)),
"recvfrom": ("long", (
("int", "sockfd"),
("void *", "buf"),
("size_t", "len"),
("unsigned", "flags"),
("struct sockaddr *", "src_addr"),
("int *", "addrlen"),
)),
"recvmmsg": ("long", (
("int", "fd"),
("struct mmsghdr *", "msg"),
("unsigned int", "vlen"),
("unsigned", "flags"),
("struct timespec *", "timeout"),
)),
"recvmsg": ("long", (
("int", "fd"),
("struct user_msghdr *", "msg"),
("unsigned", "flags"),
)),
"remap_file_pages": ("long", (
("unsigned long", "start"),
("unsigned long", "size"),
("unsigned long", "prot"),
("unsigned long", "pgoff"),
("unsigned long", "flags"),
)),
"removexattr": ("long", (
("const char *", "path"),
("const char *", "name"),
)),
"rename": ("long", (
("const char *", "oldname"),
("const char *", "newname"),
)),
"renameat": ("long", (
("int", "olddfd"),
("const char *", "oldname"),
("int", "newdfd"),
("const char *", "newname"),
)),
"renameat2": ("long", (
("int", "olddfd"),
("const char *", "oldname"),
("int", "newdfd"),
("const char *", "newname"),
("unsigned int", "flags"),
)),
"request_key": ("long", (
("const char *", "_type"),
("const char *", "_description"),
("const char *", "_callout_info"),
("key_serial_t", "destringid"),
)),
"restart_syscall": ("long", (
)),
"rmdir": ("long", (
("const char *", "pathname"),
)),
"rt_sigaction": ("long", (
("int", "signum"),
("const struct sigaction *", "act"),
("struct sigaction *", "oldact"),
("size_t", ""),
)),
"rt_sigpending": ("long", (
("sigset_t *", "set"),
("size_t", "sigsetsize"),
)),
"rt_sigprocmask": ("long", (
("int", "how"),
("sigset_t *", "set"),
("sigset_t *", "oset"),
("size_t", "sigsetsize"),
)),
"rt_sigqueueinfo": ("long", (
("int", "pid"),
("int", "sig"),
("siginfo_t *", "uinfo"),
)),
"rt_sigsuspend": ("long", (
("sigset_t *", "unewset"),
("size_t", "sigsetsize"),
)),
"rt_sigtimedwait": ("long", (
("const sigset_t *", "uthese"),
("siginfo_t *", "uinfo"),
("const struct timespec *", "uts"),
("size_t", "sigsetsize"),
)),
"rt_tgsigqueueinfo": ("long", (
("pid_t", "tgid"),
("pid_t", "pid"),
("int", "sig"),
("siginfo_t *", "uinfo"),
)),
"sched_get_priority_max": ("long", (
("int", "policy"),
)),
"sched_get_priority_min": ("long", (
("int", "policy"),
)),
"sched_getaffinity": ("long", (
("pid_t", "pid"),
("unsigned int", "len"),
("unsigned long *", "user_mask_ptr"),
)),
"sched_getattr": ("long", (
("pid_t", "pid"),
("struct sched_attr *", "attr"),
("unsigned int", "size"),
("unsigned int", "flags"),
)),
"sched_getparam": ("long", (
("pid_t", "pid"),
("struct sched_param *", "param"),
)),
"sched_getscheduler": ("long", (
("pid_t", "pid"),
)),
"sched_rr_get_interval": ("long", (
("pid_t", "pid"),
("struct timespec *", "interval"),
)),
"sched_setaffinity": ("long", (
("pid_t", "pid"),
("unsigned int", "len"),
("unsigned long *", "user_mask_ptr"),
)),
"sched_setattr": ("long", (
("pid_t", "pid"),
("struct sched_attr *", "attr"),
("unsigned int", "flags"),
)),
"sched_setparam": ("long", (
("pid_t", "pid"),
("struct sched_param *", "param"),
)),
"sched_setscheduler": ("long", (
("pid_t", "pid"),
("int", "policy"),
("struct sched_param *", "param"),
)),
"sched_yield": ("long", (
)),
"seccomp": ("long", (
("unsigned int", "op"),
("unsigned int", "flags"),
("const char *", "uargs"),
)),
"select": ("long", (
("int", "n"),
("fd_set *", "inp"),
("fd_set *", "outp"),
("fd_set *", "exp"),
("struct timeval *", "tvp"),
)),
"semctl": ("long", (
("int", "semid"),
("int", "semnum"),
("int", "cmd"),
("unsigned long", "arg"),
)),
"semget": ("long", (
("key_t", "key"),
("int", "nsems"),
("int", "semflg"),
)),
"semop": ("long", (
("int", "semid"),
("struct sembuf *", "sops"),
("unsigned", "nsops"),
)),
"semtimedop": ("long", (
("int", "semid"),
("struct sembuf *", "sops"),
("unsigned", "nsops"),
("const struct timespec *", "timeout"),
)),
"send": ("long", (
("int", "sockfd"),
("void *", "buf"),
("size_t", "len"),
("unsigned", "flags"),
)),
"sendfile": ("long", (
("int", "out_fd"),
("int", "in_fd"),
("off_t *", "offset"),
("size_t", "count"),
)),
"sendfile64": ("long", (
("int", "out_fd"),
("int", "in_fd"),
("loff_t *", "offset"),
("size_t", "count"),
)),
"sendmmsg": ("long", (
("int", "fd"),
("struct mmsghdr *", "msg"),
("unsigned int", "vlen"),
("unsigned", "flags"),
)),
"sendmsg": ("long", (
("int", "fd"),
("struct user_msghdr *", "msg"),
("unsigned", "flags"),
)),
"sendto": ("long", (
("int", "sockfd"),
("void *", "buf"),
("size_t", "len"),
("unsigned", "flags"),
("struct sockaddr *", "dest_addr"),
("int", "addrlen"),
)),
"set_mempolicy": ("long", (
("int", "mode"),
("const unsigned long *", "nmask"),
("unsigned long", "maxnode"),
)),
"set_robust_list": ("long", (
("struct robust_list_head *", "head"),
("size_t", "len"),
)),
"set_tid_address": ("long", (
("int *", "tidptr"),
)),
"setdomainname": ("long", (
("char *", "name"),
("int", "len"),
)),
"setfsgid": ("long", (
("gid_t", "gid"),
)),
"setfsgid16": ("long", (
("old_gid_t", "gid"),
)),
"setfsuid": ("long", (
("uid_t", "uid"),
)),
"setfsuid16": ("long", (
("old_uid_t", "uid"),
)),
"setgid": ("long", (
("gid_t", "gid"),
)),
"setgid16": ("long", (
("old_gid_t", "gid"),
)),
"setgroups": ("long", (
("int", "gidsetsize"),
("gid_t *", "grouplist"),
)),
"setgroups16": ("long", (
("int", "gidsetsize"),
("old_gid_t *", "grouplist"),
)),
"sethostname": ("long", (
("char *", "name"),
("int", "len"),
)),
"setitimer": ("long", (
("int", "which"),
("struct itimerval *", "value"),
("struct itimerval *", "ovalue"),
)),
"setns": ("long", (
("int", "fd"),
("int", "nstype"),
)),
"setpgid": ("long", (
("pid_t", "pid"),
("pid_t", "pgid"),
)),
"setpriority": ("long", (
("int", "which"),
("int", "who"),
("int", "niceval"),
)),
"setregid": ("long", (
("gid_t", "rgid"),
("gid_t", "egid"),
)),
"setregid16": ("long", (
("old_gid_t", "rgid"),
("old_gid_t", "egid"),
)),
"setresgid": ("long", (
("gid_t", "rgid"),
("gid_t", "egid"),
("gid_t", "sgid"),
)),
"setresgid16": ("long", (
("old_gid_t", "rgid"),
("old_gid_t", "egid"),
("old_gid_t", "sgid"),
)),
"setresuid": ("long", (
("uid_t", "ruid"),
("uid_t", "euid"),
("uid_t", "suid"),
)),
"setresuid16": ("long", (
("old_uid_t", "ruid"),
("old_uid_t", "euid"),
("old_uid_t", "suid"),
)),
"setreuid": ("long", (
("uid_t", "ruid"),
("uid_t", "euid"),
)),
"setreuid16": ("long", (
("old_uid_t", "ruid"),
("old_uid_t", "euid"),
)),
"setrlimit": ("long", (
("unsigned int", "resource"),
("struct rlimit *", "rlim"),
)),
"setsid": ("long", (
)),
"setsockopt": ("long", (
("int", "fd"),
("int", "level"),
("int", "optname"),
("char *", "optval"),
("int", "optlen"),
)),
"settimeofday": ("long", (
("struct timeval *", "tv"),
("struct timezone *", "tz"),
)),
"setuid": ("long", (
("uid_t", "uid"),
)),
"setuid16": ("long", (
("old_uid_t", "uid"),
)),
"setxattr": ("long", (
("const char *", "path"),
("const char *", "name"),
("const void *", "value"),
("size_t", "size"),
("int", "flags"),
)),
"sgetmask": ("long", (
)),
"shmat": ("long", (
("int", "shmid"),
("char *", "shmaddr"),
("int", "shmflg"),
)),
"shmctl": ("long", (
("int", "shmid"),
("int", "cmd"),
("struct shmid_ds *", "buf"),
)),
"shmdt": ("long", (
("char *", "shmaddr"),
)),
"shmget": ("long", (
("key_t", "key"),
("size_t", "size"),
("int", "flag"),
)),
"shutdown": ("long", (
("int", "sockfd"),
("int", "how"),
)),
"sigaction": ("long", (
("int", "signum"),
("const struct old_sigaction *", "act"),
("struct old_sigaction *", "oldact"),
)),
"sigaltstack": ("long", (
("const struct sigaltstack *", "uss"),
("struct sigaltstack *", "uoss"),
)),
"signal": ("long", (
("int", "sig"),
("__sighandler_t", "handler"),
)),
"signalfd": ("long", (
("int", "ufd"),
("sigset_t *", "user_mask"),
("size_t", "sizemask"),
)),
"signalfd4": ("long", (
("int", "ufd"),
("sigset_t *", "user_mask"),
("size_t", "sizemask"),
("int", "flags"),
)),
"sigpending": ("long", (
("old_sigset_t *", "set"),
)),
"sigprocmask": ("long", (
("int", "how"),
("old_sigset_t *", "set"),
("old_sigset_t *", "oset"),
)),
"sigsuspend": ("long", (
("int", "unused1"),
("int", "unused2"),
("old_sigset_t", "mask"),
)),
"socket": ("long", (
("int", "domain"),
("int", "type"),
("int", "protocol"),
)),
"socketcall": ("long", (
("int", "call"),
("unsigned long *", "args"),
)),
"socketpair": ("long", (
("int", "domain"),
("int", "type"),
("int", "protocol"),
("int *", "sv"),
)),
"splice": ("long", (
("int", "fd_in"),
("loff_t *", "off_in"),
("int", "fd_out"),
("loff_t *", "off_out"),
("size_t", "len"),
("unsigned int", "flags"),
)),
"spu_create": ("long", (
("const char *", "name"),
("unsigned int", "flags"),
("umode_t", "mode"),
("int", "fd"),
)),
"spu_run": ("long", (
("int", "fd"),
("__u32 *", "unpc"),
("__u32 *", "ustatus"),
)),
"ssetmask": ("long", (
("int", "newmask"),
)),
"stat": ("long", (
("const char *", "filename"),
("struct __old_kernel_stat *", "statbuf"),
)),
"stat64": ("long", (
("const char *", "filename"),
("struct stat64 *", "statbuf"),
)),
"statfs": ("long", (
("const char *", "path"),
("struct statfs *", "buf"),
)),
"statfs64": ("long", (
("const char *", "path"),
("size_t", "sz"),
("struct statfs64 *", "buf"),
)),
"stime": ("long", (
("time_t *", "tptr"),
)),
"swapoff": ("long", (
("const char *", "specialfile"),
)),
"swapon": ("long", (
("const char *", "specialfile"),
("int", "swap_flags"),
)),
"symlink": ("long", (
("const char *", "old"),
("const char *", "new"),
)),
"symlinkat": ("long", (
("const char *", "oldname"),
("int", "newdfd"),
("const char *", "newname"),
)),
"sync": ("long", (
)),
"sync_file_range": ("long", (
("int", "fd"),
("loff_t", "offset"),
("loff_t", "nbytes"),
("unsigned int", "flags"),
)),
"sync_file_range2": ("long", (
("int", "fd"),
("unsigned int", "flags"),
("loff_t", "offset"),
("loff_t", "nbytes"),
)),
"syncfs": ("long", (
("int", "fd"),
)),
"sysctl": ("long", (
("struct __sysctl_args *", "args"),
)),
"sysfs": ("long", (
("int", "option"),
("unsigned long", "arg1"),
("unsigned long", "arg2"),
)),
"sysinfo": ("long", (
("struct sysinfo *", "info"),
)),
"syslog": ("long", (
("int", "type"),
("char *", "buf"),
("int", "len"),
)),
"tee": ("long", (
("int", "fdin"),
("int", "fdout"),
("size_t", "len"),
("unsigned int", "flags"),
)),
"tgkill": ("long", (
("int", "tgid"),
("int", "pid"),
("int", "sig"),
)),
"time": ("long", (
("time_t *", "tloc"),
)),
"timer_create": ("long", (
("clockid_t", "which_clock"),
("struct sigevent *", "timer_event_spec"),
("timer_t *", "created_timer_id"),
)),
"timer_delete": ("long", (
("timer_t", "timer_id"),
)),
"timer_getoverrun": ("long", (
("timer_t", "timer_id"),
)),
"timer_gettime": ("long", (
("timer_t", "timer_id"),
("struct itimerspec *", "setting"),
)),
"timer_settime": ("long", (
("timer_t", "timer_id"),
("int", "flags"),
("const struct itimerspec *", "new_setting"),
("struct itimerspec *", "old_setting"),
)),
"timerfd_create": ("long", (
("int", "clockid"),
("int", "flags"),
)),
"timerfd_gettime": ("long", (
("int", "ufd"),
("struct itimerspec *", "otmr"),
)),
"timerfd_settime": ("long", (
("int", "ufd"),
("int", "flags"),
("const struct itimerspec *", "utmr"),
("struct itimerspec *", "otmr"),
)),
"times": ("long", (
("struct tms *", "tbuf"),
)),
"tkill": ("long", (
("int", "pid"),
("int", "sig"),
)),
"truncate": ("long", (
("const char *", "path"),
("long", "length"),
)),
"truncate64": ("long", (
("const char *", "path"),
("loff_t", "length"),
)),
"umask": ("long", (
("int", "mask"),
)),
"umount": ("long", (
("char *", "name"),
("int", "flags"),
)),
"uname": ("long", (
("struct old_utsname *", "buf"),
)),
"unlink": ("long", (
("const char *", "pathname"),
)),
"unlinkat": ("long", (
("int", "dfd"),
("const char *", "pathname"),
("int", "flag"),
)),
"unshare": ("long", (
("unsigned long", "unshare_flags"),
)),
"uselib": ("long", (
("const char *", "library"),
)),
"userfaultfd": ("long", (
("int", "flags"),
)),
"ustat": ("long", (
("unsigned", "dev"),
("struct ustat *", "ubuf"),
)),
"utime": ("long", (
("char *", "filename"),
("struct utimbuf *", "times"),
)),
"utimensat": ("long", (
("int", "dfd"),
("const char *", "filename"),
("struct timespec *", "utimes"),
("int", "flags"),
)),
"utimes": ("long", (
("char *", "filename"),
("struct timeval *", "utimes"),
)),
"vfork": ("long", (
)),
"vhangup": ("long", (
)),
"vmsplice": ("long", (
("int", "fd"),
("const struct iovec *", "iov"),
("unsigned long", "nr_segs"),
("unsigned int", "flags"),
)),
"wait4": ("long", (
("pid_t", "pid"),
("int *", "stat_addr"),
("int", "options"),
("struct rusage *", "ru"),
)),
"waitid": ("long", (
("int", "which"),
("pid_t", "pid"),
("struct siginfo *", "infop"),
("int", "options"),
("struct rusage *", "ru"),
)),
"waitpid": ("long", (
("pid_t", "pid"),
("int *", "stat_addr"),
("int", "options"),
)),
"write": ("long", (
("unsigned int", "fd"),
("const char *", "buf"),
("size_t", "count"),
)),
"writev": ("long", (
("unsigned long", "fd"),
("const struct iovec *", "vec"),
("unsigned long", "vlen"),
)),
}
for orig, copies in ALIASES.items():
orig = SYSCALL_PROTOTYPES[orig]
for copy in copies:
SYSCALL_PROTOTYPES[copy] = orig
python-ptrace-0.9.3/ptrace/syscall/syscall_argument.py 0000664 0001750 0001750 00000021046 13047323111 023460 0 ustar haypo haypo 0000000 0000000 from ptrace.cpu_info import CPU_WORD_SIZE
from ptrace.ctypes_tools import uint2int, formatWordHex, formatAddress
from ptrace.signames import signalName
from ctypes import c_int
from ptrace.error import PTRACE_ERRORS, writeError
from logging import getLogger, INFO
from ptrace.func_arg import FunctionArgument
from ptrace.syscall.posix_arg import (
formatMmapProt, formatAccessMode, formatOpenMode, formatCloneFlags, formatDirFd)
from ptrace.func_call import FunctionCall
from ptrace.syscall.socketcall import (setupSocketCall,
formatOptVal, formatSockaddr, formatSockaddrInStruct, formatSockaddrIn6Struct)
from ptrace.syscall.socketcall_constants import SOCKETCALL
import os
import re
from ptrace import six
from ptrace.os_tools import RUNNING_LINUX, RUNNING_FREEBSD
from ptrace.syscall import FILENAME_ARGUMENTS, DIRFD_ARGUMENTS
from ptrace.syscall.socketcall_constants import formatSocketType
if RUNNING_LINUX:
from ptrace.syscall.linux_struct import (
timeval, timespec, pollfd, rlimit, new_utsname, user_desc)
from ptrace.syscall.linux_constants import SYSCALL_ARG_DICT, FD_SETSIZE
elif RUNNING_FREEBSD:
from ptrace.syscall.freebsd_constants import SYSCALL_ARG_DICT
else:
SYSCALL_ARG_DICT = {}
KNOWN_STRUCTS = []
if RUNNING_LINUX:
KNOWN_STRUCTS.extend(
(timeval, timespec, pollfd, rlimit, new_utsname, user_desc))
KNOWN_STRUCTS = dict((struct.__name__, struct) for struct in KNOWN_STRUCTS)
ARGUMENT_CALLBACK = {
# Prototype: callback(argument) -> str
"access": {"mode": formatAccessMode},
"open": {"flags": formatOpenMode, "mode": formatOpenMode},
"openat": {"flags": formatOpenMode, "mode": formatOpenMode},
"mmap": {"prot": formatMmapProt},
"mmap2": {"prot": formatMmapProt},
"clone": {"flags": formatCloneFlags},
"socket": {"type": formatSocketType},
"setsockopt": {"optval": formatOptVal},
}
POINTER_CALLBACK = {
# Prototype: callback(argument, argtype) -> str
"sockaddr": formatSockaddr,
}
STRUCT_CALLBACK = {
# Prototype: callback(argument, attr_name, attr_value) -> str
"sockaddr_in": formatSockaddrInStruct,
"sockaddr_in6": formatSockaddrIn6Struct,
}
INTEGER_TYPES = set((
"int", "size_t", "clockid_t", "long",
"socklen_t", "pid_t", "uid_t", "gid_t",
))
def iterBits(data):
for char in data:
byte = ord(char)
for index in range(8):
yield ((byte >> index) & 1) == 1
class SyscallArgument(FunctionArgument):
def createText(self):
value = self.value
argtype = self.type
name = self.name
if not argtype or not name:
return formatWordHex(self.value)
syscall = self.function.name
# Special cases
try:
return SYSCALL_ARG_DICT[syscall][name][value]
except KeyError:
pass
try:
callback = ARGUMENT_CALLBACK[syscall][name]
except KeyError:
callback = None
if callback:
return callback(self)
if syscall == "execve":
if name in ("argv", "envp"):
return self.readCStringArray(value)
if syscall == "socketcall":
if name == "call":
try:
return SOCKETCALL[value]
except KeyError:
return str(value)
if name == "args":
func_call = FunctionCall("socketcall", self.options)
setupSocketCall(func_call, self.function.process,
self.function[0], self.value)
text = "<%s>" % func_call.format()
return self.formatPointer(text, self.value)
if syscall == "write" and name == "buf":
fd = self.function[0].value
if fd < 3:
length = self.function[2].value
return self.readString(value, length)
if name == "signum":
return signalName(value)
if name in DIRFD_ARGUMENTS and argtype == "int":
return formatDirFd(uint2int(value))
# Remove "const " prefix
if argtype.startswith("const "):
argtype = argtype[6:]
if name in FILENAME_ARGUMENTS and argtype == "char *":
return self.readCString(value)
# Format depending on the type
if argtype.endswith("*"):
try:
text = self.formatValuePointer(argtype[:-1])
if text:
return text
except PTRACE_ERRORS as err:
writeError(
getLogger(), err, "Warning: Format %r value error" % self, log_level=INFO)
return formatAddress(self.value)
# Array like "int[2]"
match = re.match("(.*)\[([0-9])+\]", argtype)
if match:
basetype = match.group(1)
count = int(match.group(2))
if basetype == "int":
return self.readArray(self.value, c_int, count)
# Simple types
if argtype in ("unsigned int", "unsigned long", "u32"):
return str(self.value)
if argtype in INTEGER_TYPES:
return str(uint2int(self.value))
# Default formatter: hexadecimal
return formatWordHex(self.value)
def formatValuePointer(self, argtype):
address = self.value
if not address:
return "NULL"
if argtype.startswith("struct "):
argtype = argtype[7:]
# Try a callback
try:
callback = POINTER_CALLBACK[argtype]
except KeyError:
callback = None
if callback:
return callback(self, argtype)
if argtype == "int":
pointee = self.function.process.readStruct(address, c_int)
return self.formatPointer("<%s>" % pointee, address)
if argtype in KNOWN_STRUCTS:
struct = KNOWN_STRUCTS[argtype]
return self.readStruct(address, struct)
if RUNNING_LINUX and argtype == "fd_set":
fd_set = self.readBits(address, FD_SETSIZE)
return self.formatPointer("" % fd_set, address)
syscall = self.function.name
if syscall == "rt_sigprocmask" and argtype == "sigset_t":
size = self.function["sigsetsize"].value * 8
def formatter(key):
key += 1
return signalName(key)
fd_set = self.readBits(address, size, format=formatter)
return self.formatPointer("" % fd_set, address)
return None
def readBits(self, address, count, format=str):
bytes = self.function.process.readBytes(address, count // 8)
fd_set = [format(index)
for index, bit in enumerate(iterBits(bytes)) if bit]
return ", ".join(fd_set)
def readCString(self, address):
if address:
max_size = self.options.string_max_length
data, truncated = self.function.process.readCString(
address, max_size)
if six.PY3:
text = os.fsdecode(data)
else:
text = data
text = repr(text)
if truncated:
text += "..."
else:
text = "NULL"
return self.formatPointer(text, address)
def readString(self, address, size):
if address:
max_len = self.options.string_max_length
truncated = (max_len < size)
size = min(size, max_len)
data = self.function.process.readBytes(address, size)
if six.PY3:
text = os.fsdecode(data)
else:
text = data
text = repr(text)
if truncated:
text += "..."
else:
text = "NULL"
return self.formatPointer(text, address)
def readCStringArray(self, address):
if not address:
return "NULL"
address0 = address
max_count = self.options.max_array_count
text = []
while True:
str_addr = self.function.process.readWord(address)
address += CPU_WORD_SIZE
text.append(self.readCString(str_addr))
if not str_addr:
break
if max_count <= len(text):
text.append("(... more than %s strings ...)" % max_count)
break
text = "<(%s)>" % ", ".join(text)
return self.formatPointer(text, address0)
def formatStructValue(self, struct, name, value):
if struct in STRUCT_CALLBACK:
callback = STRUCT_CALLBACK[struct]
return callback(self, name, value)
return None
python-ptrace-0.9.3/ptrace/syscall/__init__.py 0000664 0001750 0001750 00000000544 13047323112 021644 0 ustar haypo haypo 0000000 0000000 from ptrace.syscall.names import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES # noqa
from ptrace.syscall.prototypes import SYSCALL_PROTOTYPES, FILENAME_ARGUMENTS, DIRFD_ARGUMENTS # noqa
from ptrace.syscall.syscall_argument import SyscallArgument # noqa
from ptrace.syscall.ptrace_syscall import PtraceSyscall, SYSCALL_REGISTER, RETURN_VALUE_REGISTER # noqa
python-ptrace-0.9.3/ptrace/syscall/posix_constants.py 0000664 0001750 0001750 00000002740 13047323111 023342 0 ustar haypo haypo 0000000 0000000 from ptrace.syscall.socketcall_constants import (
SOCKET_FAMILY, SOCKET_PROTOCOL,
SETSOCKOPT_LEVEL, SETSOCKOPT_OPTNAME)
SYSCALL_ARG_DICT = {
"lseek": {
"origin": {0: "SEEK_SET", 1: "SEEK_CUR", 2: "SEEK_END"},
},
"futex": {
"op": {
0: "FUTEX_WAIT",
1: "FUTEX_WAKE",
2: "FUTEX_FD",
3: "FUTEX_REQUEUE",
4: "FUTEX_CMP_REQUEUE",
5: "FUTEX_WAKE_OP",
6: "FUTEX_LOCK_PI",
7: "FUTEX_UNLOCK_PI",
8: "FUTEX_TRYLOCK_PI",
},
},
"fcntl": {
"cmd": {
0: "F_DUPFD",
1: "F_GETFD",
2: "F_SETFD",
3: "F_GETFL",
4: "F_SETFL",
5: "F_GETOWN",
6: "F_SETOWN",
7: "F_GETLK",
8: "F_SETLK",
9: "F_SETLKW",
},
},
"ipc": {
"call": {
1: "SEMOP",
2: "SEMGET",
3: "SEMCTL",
4: "SEMTIMEDOP",
11: "MSGSND",
12: "MSGRCV",
13: "MSGGET",
14: "MSGCTL",
21: "SHMAT",
22: "SHMDT",
23: "SHMGET",
24: "SHMCTL",
},
},
"socket": {
"domain": SOCKET_FAMILY,
"protocol": SOCKET_PROTOCOL,
},
"getsockopt": {
"level": SETSOCKOPT_LEVEL,
"optname": SETSOCKOPT_OPTNAME,
},
}
SYSCALL_ARG_DICT["setsockopt"] = SYSCALL_ARG_DICT["getsockopt"]
python-ptrace-0.9.3/ptrace/syscall/posix_arg.py 0000664 0001750 0001750 00000005270 13047323324 022106 0 ustar haypo haypo 0000000 0000000 from ptrace.tools import readBits, formatBits
from ptrace.signames import signalName
# From /usr/include/bits/mman.h (Ubuntu Feisty, i386)
MMAP_PROT_BITMASK = (
(1, "PROT_READ"),
(2, "PROT_WRITE"),
(4, "PROT_EXEC"),
(0x01000000, "PROT_GROWSDOWN"),
(0x02000000, "PROT_GROWSUP"),
)
def formatMmapProt(argument):
return formatBits(argument.value, MMAP_PROT_BITMASK, "PROT_NONE")
# From /usr/include/bits/mman.h (Ubuntu Feisty, i386)
ACCESS_MODE_BITMASK = (
(1, "X_OK"),
(2, "W_OK"),
(4, "R_OK"),
)
def formatAccessMode(argument):
return formatBits(argument.value, ACCESS_MODE_BITMASK, "F_OK")
# From /usr/include/bits/fcntl.h (Ubuntu Feisty, i386)
OPEN_MODE_BITMASK = [
(0o1, "O_WRONLY"),
(0o2, "O_RDWR"),
(0o100, "O_CREAT"),
(0o200, "O_EXCL"),
(0o400, "O_NOCTTY"),
(0o1000, "O_TRUNC"),
(0o2000, "O_APPEND"),
(0o4000, "O_NONBLOCK"),
(0o10000, "O_SYNC"),
(0o20000, "O_ASYNC"),
(0o40000, "O_DIRECT"),
(0o100000, "O_LARGEFILE"),
(0o200000, "O_DIRECTORY"),
(0o400000, "O_NOFOLLOW"),
(0o1000000, "O_NOATIME"),
(0o2000000, "O_CLOEXEC"),
(0o10000000, "O_PATH"), # Linux 2.6.39
(0o20200000, "O_TMPFILE"), # Linux 3.11
]
def formatOpenMode(argument):
value = argument.value
flags = readBits(int(value), OPEN_MODE_BITMASK)
# Add default access mode if neither of the others are present.
if not flags or flags[0] not in ("O_WRONLY", "O_RDWR"):
flags.insert(0, "O_RDONLY")
text = "|".join(flags)
if value:
text = "%s (%s)" % (text, oct(argument.value))
return text
CLONE_FLAGS_BITMASK = (
(0x00000100, "CLONE_VM"),
(0x00000200, "CLONE_FS"),
(0x00000400, "CLONE_FILES"),
(0x00000800, "CLONE_SIGHAND"),
(0x00002000, "CLONE_PTRACE"),
(0x00004000, "CLONE_VFORK"),
(0x00008000, "CLONE_PARENT"),
(0x00010000, "CLONE_THREAD"),
(0x00020000, "CLONE_NEWNS"),
(0x00040000, "CLONE_SYSVSEM"),
(0x00080000, "CLONE_SETTLS"),
(0x00100000, "CLONE_PARENT_SETTID"),
(0x00200000, "CLONE_CHILD_CLEARTID"),
(0x00400000, "CLONE_DETACHED"),
(0x00800000, "CLONE_UNTRACED"),
(0x01000000, "CLONE_CHILD_SETTID"),
(0x02000000, "CLONE_STOPPED"),
(0x04000000, "CLONE_NEWUTS"),
(0x08000000, "CLONE_NEWIPC"),
)
def formatCloneFlags(argument):
flags = argument.value
bits = readBits(flags, CLONE_FLAGS_BITMASK)
signum = flags & 0xFF
if signum:
bits.insert(0, signalName(signum))
if bits:
bits = "%s" % ("|".join(bits))
return "<%s> (%s)" % (bits, str(flags))
else:
return str(flags)
AT_FDCWD = -100
def formatDirFd(value):
return "AT_FDCWD" if value == AT_FDCWD else str(value)
python-ptrace-0.9.3/ptrace/syscall/linux_syscall64.py 0000664 0001750 0001750 00000014272 13047323112 023153 0 ustar haypo haypo 0000000 0000000 # Linux kernel 2.6.23 on Intel Core2 Duo E6400
SYSCALL_NAMES = {
0: "read",
1: "write",
2: "open",
3: "close",
4: "stat",
5: "fstat",
6: "lstat",
7: "poll",
8: "lseek",
9: "mmap",
10: "mprotect",
11: "munmap",
12: "brk",
13: "rt_sigaction",
14: "rt_sigprocmask",
15: "rt_sigreturn",
16: "ioctl",
17: "pread64",
18: "pwrite64",
19: "readv",
20: "writev",
21: "access",
22: "pipe",
23: "select",
24: "sched_yield",
25: "mremap",
26: "msync",
27: "mincore",
28: "madvise",
29: "shmget",
30: "shmat",
31: "shmctl",
32: "dup",
33: "dup2",
34: "pause",
35: "nanosleep",
36: "getitimer",
37: "alarm",
38: "setitimer",
39: "getpid",
40: "sendfile",
41: "socket",
42: "connect",
43: "accept",
44: "sendto",
45: "recvfrom",
46: "sendmsg",
47: "recvmsg",
48: "shutdown",
49: "bind",
50: "listen",
51: "getsockname",
52: "getpeername",
53: "socketpair",
54: "setsockopt",
55: "getsockopt",
56: "clone",
57: "fork",
58: "vfork",
59: "execve",
60: "exit",
61: "wait4",
62: "kill",
63: "uname",
64: "semget",
65: "semop",
66: "semctl",
67: "shmdt",
68: "msgget",
69: "msgsnd",
70: "msgrcv",
71: "msgctl",
72: "fcntl",
73: "flock",
74: "fsync",
75: "fdatasync",
76: "truncate",
77: "ftruncate",
78: "getdents",
79: "getcwd",
80: "chdir",
81: "fchdir",
82: "rename",
83: "mkdir",
84: "rmdir",
85: "creat",
86: "link",
87: "unlink",
88: "symlink",
89: "readlink",
90: "chmod",
91: "fchmod",
92: "chown",
93: "fchown",
94: "lchown",
95: "umask",
96: "gettimeofday",
97: "getrlimit",
98: "getrusage",
99: "sysinfo",
100: "times",
101: "ptrace",
102: "getuid",
103: "syslog",
104: "getgid",
105: "setuid",
106: "setgid",
107: "geteuid",
108: "getegid",
109: "setpgid",
110: "getppid",
111: "getpgrp",
112: "setsid",
113: "setreuid",
114: "setregid",
115: "getgroups",
116: "setgroups",
117: "setresuid",
118: "getresuid",
119: "setresgid",
120: "getresgid",
121: "getpgid",
122: "setfsuid",
123: "setfsgid",
124: "getsid",
125: "capget",
126: "capset",
127: "rt_sigpending",
128: "rt_sigtimedwait",
129: "rt_sigqueueinfo",
130: "rt_sigsuspend",
131: "sigaltstack",
132: "utime",
133: "mknod",
134: "uselib",
135: "personality",
136: "ustat",
137: "statfs",
138: "fstatfs",
139: "sysfs",
140: "getpriority",
141: "setpriority",
142: "sched_setparam",
143: "sched_getparam",
144: "sched_setscheduler",
145: "sched_getscheduler",
146: "sched_get_priority_max",
147: "sched_get_priority_min",
148: "sched_rr_get_interval",
149: "mlock",
150: "munlock",
151: "mlockall",
152: "munlockall",
153: "vhangup",
154: "modify_ldt",
155: "pivot_root",
156: "_sysctl",
157: "prctl",
158: "arch_prctl",
159: "adjtimex",
160: "setrlimit",
161: "chroot",
162: "sync",
163: "acct",
164: "settimeofday",
165: "mount",
166: "umount2",
167: "swapon",
168: "swapoff",
169: "reboot",
170: "sethostname",
171: "setdomainname",
172: "iopl",
173: "ioperm",
174: "create_module",
175: "init_module",
176: "delete_module",
177: "get_kernel_syms",
178: "query_module",
179: "quotactl",
180: "nfsservctl",
181: "getpmsg",
182: "putpmsg",
183: "afs_syscall",
184: "tuxcall",
185: "security",
186: "gettid",
187: "readahead",
188: "setxattr",
189: "lsetxattr",
190: "fsetxattr",
191: "getxattr",
192: "lgetxattr",
193: "fgetxattr",
194: "listxattr",
195: "llistxattr",
196: "flistxattr",
197: "removexattr",
198: "lremovexattr",
199: "fremovexattr",
200: "tkill",
201: "time",
202: "futex",
203: "sched_setaffinity",
204: "sched_getaffinity",
205: "set_thread_area",
206: "io_setup",
207: "io_destroy",
208: "io_getevents",
209: "io_submit",
210: "io_cancel",
211: "get_thread_area",
212: "lookup_dcookie",
213: "epoll_create",
214: "epoll_ctl_old",
215: "epoll_wait_old",
216: "remap_file_pages",
217: "getdents64",
218: "set_tid_address",
219: "restart_syscall",
220: "semtimedop",
221: "fadvise64",
222: "timer_create",
223: "timer_settime",
224: "timer_gettime",
225: "timer_getoverrun",
226: "timer_delete",
227: "clock_settime",
228: "clock_gettime",
229: "clock_getres",
230: "clock_nanosleep",
231: "exit_group",
232: "epoll_wait",
233: "epoll_ctl",
234: "tgkill",
235: "utimes",
236: "vserver",
237: "mbind",
238: "set_mempolicy",
239: "get_mempolicy",
240: "mq_open",
241: "mq_unlink",
242: "mq_timedsend",
243: "mq_timedreceive",
244: "mq_notify",
245: "mq_getsetattr",
246: "kexec_load",
247: "waitid",
248: "add_key",
249: "request_key",
250: "keyctl",
251: "ioprio_set",
252: "ioprio_get",
253: "inotify_init",
254: "inotify_add_watch",
255: "inotify_rm_watch",
256: "migrate_pages",
257: "openat",
258: "mkdirat",
259: "mknodat",
260: "fchownat",
261: "futimesat",
262: "newfstatat",
263: "unlinkat",
264: "renameat",
265: "linkat",
266: "symlinkat",
267: "readlinkat",
268: "fchmodat",
269: "faccessat",
270: "pselect6",
271: "ppoll",
272: "unshare",
273: "set_robust_list",
274: "get_robust_list",
275: "splice",
276: "tee",
277: "sync_file_range",
278: "vmsplice",
279: "move_pages",
280: "utimensat",
281: "epoll_pwait",
282: "signalfd",
283: "timerfd",
284: "eventfd",
285: "fallocate",
}
SOCKET_SYSCALL_NAMES = set((
"socket", "socketpair", "connect",
"sendto", "recvfrom", "sendmsg", "recvmsg",
"bind", "listen", "accept",
"getsockname", "getpeername", "getsockopt", "setsockopt",
"shutdown",
))
python-ptrace-0.9.3/ptrace/syscall/linux_syscall32.py 0000664 0001750 0001750 00000015547 13047323111 023153 0 ustar haypo haypo 0000000 0000000 # Linux kernel syscall list from Linux 2.6.21 for i386
#
# List extracted from Linux kernel source code, see:
# arch/i386/kernel/syscall_table.S
SYSCALL_NAMES = {
0: "restart_syscall",
1: "exit",
2: "fork",
3: "read",
4: "write",
5: "open",
6: "close",
7: "waitpid",
8: "creat",
9: "link",
10: "unlink",
11: "execve",
12: "chdir",
13: "time",
14: "mknod",
15: "chmod",
16: "lchown16",
# 17: -
18: "stat",
19: "lseek",
20: "getpid",
21: "mount",
22: "oldumount",
23: "setuid16",
24: "getuid16",
25: "stime",
26: "ptrace",
27: "alarm",
28: "fstat",
29: "pause",
30: "utime",
# 31: -
# 32: -
33: "access",
34: "nice",
# 35: -
36: "sync",
37: "kill",
38: "rename",
39: "mkdir",
40: "rmdir",
41: "dup",
42: "pipe",
43: "times",
# 44: -
45: "brk",
46: "setgid16",
47: "getgid16",
48: "signal",
49: "geteuid16",
50: "getegid16",
51: "acct",
52: "umount",
# 53: -
54: "ioctl",
55: "fcntl",
# 56: -
57: "setpgid",
# 58: -
59: "oldolduname",
60: "umask",
61: "chroot",
62: "ustat",
63: "dup2",
64: "getppid",
65: "getpgrp",
66: "setsid",
67: "sigaction",
68: "sgetmask",
69: "ssetmask",
70: "setreuid16",
71: "setregid16",
72: "sigsuspend",
73: "sigpending",
74: "sethostname",
75: "setrlimit",
76: "old_getrlimit",
77: "getrusage",
78: "gettimeofday",
79: "settimeofday",
80: "getgroups16",
81: "setgroups16",
82: "old_select",
83: "symlink",
84: "lstat",
85: "readlink",
86: "uselib",
87: "swapon",
88: "reboot",
89: "old_readdir",
90: "old_mmap",
91: "munmap",
92: "truncate",
93: "ftruncate",
94: "fchmod",
95: "fchown16",
96: "getpriority",
97: "setpriority",
# 98: -
99: "statfs",
100: "fstatfs",
101: "ioperm",
102: "socketcall",
103: "syslog",
104: "setitimer",
105: "getitimer",
106: "newstat",
107: "newlstat",
108: "newfstat",
109: "olduname",
110: "iopl",
111: "vhangup",
# 112: old "idle"
113: "vm86old",
114: "wait4",
115: "swapoff",
116: "sysinfo",
117: "ipc",
118: "fsync",
119: "sigreturn",
120: "clone",
121: "setdomainname",
122: "uname",
123: "modify_ldt",
124: "adjtimex",
125: "mprotect",
126: "sigprocmask",
# 127: old "create_module"
128: "init_module",
129: "delete_module",
# 130: old "get_kernel_syms"
131: "quotactl",
132: "getpgid",
133: "fchdir",
134: "bdflush",
135: "sysfs",
136: "personality",
# 137: reserved for afs_syscall
138: "setfsuid16",
139: "setfsgid16",
140: "llseek",
141: "getdents",
142: "select",
143: "flock",
144: "msync",
145: "readv",
146: "writev",
147: "getsid",
148: "fdatasync",
149: "sysctl",
150: "mlock",
151: "munlock",
152: "mlockall",
153: "munlockall",
154: "sched_setparam",
155: "sched_getparam",
156: "sched_setscheduler",
157: "sched_getscheduler",
158: "sched_yield",
159: "sched_get_priority_max",
160: "sched_get_priority_min",
161: "sched_rr_get_interval",
162: "nanosleep",
163: "mremap",
164: "setresuid16",
165: "getresuid16",
166: "vm86",
# 167: old "query_module"
168: "poll",
169: "nfsservctl",
170: "setresgid16",
171: "getresgid16",
172: "prctl",
173: "rt_sigreturn",
174: "rt_sigaction",
175: "rt_sigprocmask",
176: "rt_sigpending",
177: "rt_sigtimedwait",
178: "rt_sigqueueinfo",
179: "rt_sigsuspend",
180: "pread64",
181: "pwrite64",
182: "chown16",
183: "getcwd",
184: "capget",
185: "capset",
186: "sigaltstack",
187: "sendfile",
# 188: (reserved)
# 189: (reserved)
190: "vfork",
191: "getrlimit",
192: "mmap2",
193: "truncate64",
194: "ftruncate64",
195: "stat64",
196: "lstat64",
197: "fstat64",
198: "lchown",
199: "getuid",
200: "getgid",
201: "geteuid",
202: "getegid",
203: "setreuid",
204: "setregid",
205: "getgroups",
206: "setgroups",
207: "fchown",
208: "setresuid",
209: "getresuid",
210: "setresgid",
211: "getresgid",
212: "chown",
213: "setuid",
214: "setgid",
215: "setfsuid",
216: "setfsgid",
# -------------------------------
217: "pivot_root",
218: "mincore",
219: "madvise",
220: "getdents64",
221: "fcntl64",
# 222: -
# 223: -
224: "gettid",
225: "readahead",
226: "setxattr",
227: "lsetxattr",
228: "fsetxattr",
229: "getxattr",
230: "lgetxattr",
231: "fgetxattr",
232: "listxattr",
233: "llistxattr",
234: "flistxattr",
235: "removexattr",
236: "lremovexattr",
237: "fremovexattr",
238: "tkill",
239: "sendfile64",
240: "futex",
241: "sched_setaffinity",
242: "sched_getaffinity",
243: "set_thread_area",
244: "get_thread_area",
245: "io_setup",
246: "io_destroy",
247: "io_getevents",
248: "io_submit",
249: "io_cancel",
250: "fadvise64",
# 251: -
252: "exit_group",
253: "lookup_dcookie",
254: "epoll_create",
255: "epoll_ctl",
256: "epoll_wait",
257: "remap_file_pages",
258: "set_tid_address",
259: "timer_create",
260: "timer_settime",
261: "timer_gettime",
262: "timer_getoverrun",
263: "timer_delete",
264: "clock_settime",
265: "clock_gettime",
266: "clock_getres",
267: "clock_nanosleep",
268: "statfs64",
269: "fstatfs64",
270: "tgkill",
271: "utimes",
272: "fadvise64_64",
# 273: -
274: "mbind",
275: "get_mempolicy",
276: "set_mempolicy",
277: "mq_open",
278: "mq_unlink",
279: "mq_timedsend",
280: "mq_timedreceive",
281: "mq_notify",
282: "mq_getsetattr",
283: "kexec_load",
284: "waitid",
# 285: -
286: "add_key",
287: "request_key",
288: "keyctl",
289: "ioprio_set",
290: "ioprio_get",
291: "inotify_init",
292: "inotify_add_watch",
293: "inotify_rm_watch",
294: "migrate_pages",
295: "openat",
296: "mkdirat",
297: "mknodat",
298: "fchownat",
299: "futimesat",
300: "fstatat64",
301: "unlinkat",
302: "renameat",
303: "linkat",
304: "symlinkat",
305: "readlinkat",
306: "fchmodat",
307: "faccessat",
308: "pselect6",
309: "ppoll",
310: "unshare",
311: "set_robust_list",
312: "get_robust_list",
313: "splice",
314: "sync_file_range",
315: "tee",
316: "vmsplice",
317: "move_pages",
318: "getcpu",
319: "epoll_pwait",
}
SOCKET_SYSCALL_NAMES = set(("socketcall",))
python-ptrace-0.9.3/ptrace/syscall/socketcall_struct.py 0000664 0001750 0001750 00000004722 13047323324 023644 0 ustar haypo haypo 0000000 0000000 from ctypes import Structure, Union, c_char, c_ushort, c_ubyte, c_uint16, c_uint32
from ptrace.os_tools import RUNNING_BSD, RUNNING_LINUX
from socket import inet_ntoa
from struct import pack
from ptrace.ctypes_tools import ntoh_uint, ntoh_ushort
def ip_int2str(ip):
"""
Convert an IP address (as an integer) to a string.
>>> ip_int2str(0x7f000001)
'127.0.0.1'
"""
ip_bytes = pack("!I", ip)
return inet_ntoa(ip_bytes)
if RUNNING_BSD:
sa_family_t = c_ubyte
else:
sa_family_t = c_ushort
class sockaddr(Structure):
if RUNNING_BSD:
_fields_ = (
("len", c_ubyte),
("family", sa_family_t),
)
else:
_fields_ = (
("family", sa_family_t),
)
class in_addr(Structure):
_fields_ = (
("s_addr", c_uint32),
)
def __repr__(self):
ip = ntoh_uint(self.s_addr)
return ip_int2str(ip)
class in6_addr(Union):
_fields_ = (
("addr8", c_ubyte * 16),
("addr16", c_uint16 * 8),
("addr32", c_uint32 * 4),
)
def __repr__(self):
text = ':'.join(("%04x" % ntoh_ushort(part)) for part in self.addr16)
return "" % text
# INET socket
class sockaddr_in(Structure):
if RUNNING_BSD:
_fields_ = (
("sin_len", c_ubyte),
("sin_family", sa_family_t),
("sin_port", c_uint16),
("sin_addr", in_addr),
)
else:
_fields_ = (
("sin_family", sa_family_t),
("sin_port", c_uint16),
("sin_addr", in_addr),
)
class sockaddr_in6(Structure):
if RUNNING_BSD:
_fields_ = (
("sin6_len", c_ubyte),
("sin6_family", sa_family_t),
("sin6_port", c_uint16),
("sin6_flowinfo", c_uint32),
("sin6_addr", in6_addr),
)
else:
_fields_ = (
("sin6_family", sa_family_t),
("sin6_port", c_uint16),
("sin6_flowinfo", c_uint32),
("sin6_addr", in6_addr),
("sin6_scope_ip", c_uint32),
)
# UNIX socket
class sockaddr_un(Structure):
_fields_ = (
("sun_family", sa_family_t),
("sun_path", c_char * 108),
)
# Netlink socket
if RUNNING_LINUX:
class sockaddr_nl(Structure):
_fields_ = (
("nl_family", sa_family_t),
("nl_pad", c_ushort),
("nl_pid", c_uint32),
("nl_groups", c_uint32),
)
python-ptrace-0.9.3/ptrace/syscall/freebsd_constants.py 0000664 0001750 0001750 00000001162 13047323112 023610 0 ustar haypo haypo 0000000 0000000 from ptrace.syscall.posix_constants import SYSCALL_ARG_DICT
RLIMIT_RESOURCE = {
0: "RLIMIT_CPU",
1: "RLIMIT_FSIZE",
2: "RLIMIT_DATA",
3: "RLIMIT_STACK",
4: "RLIMIT_CORE",
5: "RLIMIT_RSS",
6: "RLIMIT_MEMLOCK",
7: "RLIMIT_NPROC",
8: "RLIMIT_NOFILE",
9: "RLIMIT_SBSIZE",
10: "RLIMIT_VMEM",
}
SIGPROCMASK_HOW = {1: " SIG_BLOCK", 2: "SIG_UNBLOCK", 3: "SIG_SETMASK"}
SYSCALL_ARG_DICT.update({
"getrlimit": {"resource": RLIMIT_RESOURCE},
"setrlimit": {"resource": RLIMIT_RESOURCE},
"sigprocmask": {"how": SIGPROCMASK_HOW},
"rt_sigprocmask": {"how": SIGPROCMASK_HOW},
})
python-ptrace-0.9.3/ptrace/syscall/socketcall.py 0000664 0001750 0001750 00000004500 13047323113 022226 0 ustar haypo haypo 0000000 0000000 from ptrace.cpu_info import CPU_WORD_SIZE
from ptrace.ctypes_tools import ntoh_ushort, ntoh_uint # noqa
from ptrace.syscall import SYSCALL_PROTOTYPES
from ptrace.syscall.socketcall_constants import SOCKETCALL, SOCKET_FAMILY # noqa
from ptrace.syscall.socketcall_struct import sockaddr, sockaddr_in, sockaddr_in6, sockaddr_un
from ctypes import c_int
from ptrace.os_tools import RUNNING_LINUX
from socket import AF_INET, AF_INET6, inet_ntoa # noqa
if RUNNING_LINUX:
from socket import AF_NETLINK
from ptrace.syscall.socketcall_struct import sockaddr_nl
AF_FILE = 1
def formatOptVal(argument):
function = argument.function
optlen = function["optlen"].value
if optlen == 4:
addr = argument.value
text = function.process.readStruct(addr, c_int)
return argument.formatPointer("<%s>" % text, addr)
else:
return None
def formatSockaddr(argument, argtype):
address = argument.value
value = argument.function.process.readStruct(address, sockaddr)
family = value.family
if family == AF_INET:
return argument.readStruct(address, sockaddr_in)
if family == AF_INET6:
return argument.readStruct(address, sockaddr_in6)
if family == AF_FILE:
return argument.readStruct(address, sockaddr_un)
if RUNNING_LINUX:
if family == AF_NETLINK:
return argument.readStruct(address, sockaddr_nl)
family = SOCKET_FAMILY.get(family, family)
return argument.formatPointer("" % family, address)
def setupSocketCall(function, process, socketcall, address):
# Reset function call
function.clearArguments()
# function.argument_class = SocketCallArgument
# Setup new function call
function.process = process
function.name = socketcall.getText()
# Create arguments
function.restype, formats = SYSCALL_PROTOTYPES[function.name]
for argtype, argname in formats:
value = process.readWord(address)
function.addArgument(value, argname, argtype)
address += CPU_WORD_SIZE
def formatSockaddrInStruct(argument, name, value):
if name == "sin_port":
return ntoh_ushort(value)
return None
def formatSockaddrIn6Struct(argument, name, value):
if name == "sin6_port":
return ntoh_ushort(value)
# if name == "sin6_addr":
# FIXME: ...
return None
python-ptrace-0.9.3/ptrace/syscall/names.py 0000664 0001750 0001750 00000000746 13047323112 021214 0 ustar haypo haypo 0000000 0000000 from ptrace.cpu_info import CPU_64BITS
from ptrace.os_tools import RUNNING_LINUX, RUNNING_FREEBSD
if RUNNING_LINUX:
if CPU_64BITS:
from ptrace.syscall.linux_syscall64 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES
else:
from ptrace.syscall.linux_syscall32 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES
elif RUNNING_FREEBSD:
from ptrace.syscall.freebsd_syscall import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES
else:
SYSCALL_NAMES = {}
SOCKET_SYSCALL_NAMES = set()
python-ptrace-0.9.3/ptrace/syscall/ptrace_syscall.py 0000664 0001750 0001750 00000011633 13047323113 023117 0 ustar haypo haypo 0000000 0000000 from os import strerror
from errno import errorcode
from ptrace.cpu_info import CPU_X86_64, CPU_POWERPC, CPU_I386, CPU_ARM
from ptrace.ctypes_tools import ulong2long, formatAddress, formatWordHex
from ptrace.func_call import FunctionCall
from ptrace.syscall import SYSCALL_NAMES, SYSCALL_PROTOTYPES, SyscallArgument
from ptrace.syscall.socketcall import setupSocketCall
from ptrace.os_tools import RUNNING_LINUX, RUNNING_BSD
from ptrace.cpu_info import CPU_WORD_SIZE
from ptrace.binding.cpu import CPU_INSTR_POINTER
if CPU_POWERPC:
SYSCALL_REGISTER = "gpr0"
elif CPU_ARM:
SYSCALL_REGISTER = "r7"
elif RUNNING_LINUX:
if CPU_X86_64:
SYSCALL_REGISTER = "orig_rax"
else:
SYSCALL_REGISTER = "orig_eax"
else:
if CPU_X86_64:
SYSCALL_REGISTER = "rax"
else:
SYSCALL_REGISTER = "eax"
if CPU_ARM:
RETURN_VALUE_REGISTER = "r0"
elif CPU_I386:
RETURN_VALUE_REGISTER = "eax"
elif CPU_X86_64:
RETURN_VALUE_REGISTER = "rax"
elif CPU_POWERPC:
RETURN_VALUE_REGISTER = "result"
else:
raise NotImplementedError("Unsupported CPU architecture")
PREFORMAT_ARGUMENTS = {
"select": (2, 3, 4),
"execve": (0, 1, 2),
"clone": (0, 1),
}
class PtraceSyscall(FunctionCall):
def __init__(self, process, options, regs=None):
FunctionCall.__init__(self, "syscall", options, SyscallArgument)
self.process = process
self.restype = "long"
self.result = None
self.result_text = None
self.instr_pointer = None
if not regs:
regs = self.process.getregs()
self.readSyscall(regs)
def enter(self, regs=None):
if not regs:
regs = self.process.getregs()
argument_values = self.readArgumentValues(regs)
self.readArguments(argument_values)
if self.name == "socketcall" and self.options.replace_socketcall:
setupSocketCall(self, self.process, self[0], self[1].value)
# Some arguments are lost after the syscall, so format them now
if self.name in PREFORMAT_ARGUMENTS:
for index in PREFORMAT_ARGUMENTS[self.name]:
argument = self.arguments[index]
argument.format()
if self.options.instr_pointer:
self.instr_pointer = getattr(regs, CPU_INSTR_POINTER)
def readSyscall(self, regs):
# Read syscall number
self.syscall = getattr(regs, SYSCALL_REGISTER)
# Get syscall variables
self.name = SYSCALL_NAMES.get(
self.syscall, "syscall<%s>" % self.syscall)
def readArgumentValues(self, regs):
if CPU_X86_64:
return (regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9)
if CPU_ARM:
return (regs.r0, regs.r1, regs.r2, regs.r3, regs.r4, regs.r5, regs.r6)
if RUNNING_BSD:
sp = self.process.getStackPointer()
return [self.process.readWord(sp + index * CPU_WORD_SIZE)
for index in range(1, 6 + 1)]
if CPU_I386:
return (regs.ebx, regs.ecx, regs.edx, regs.esi, regs.edi, regs.ebp)
if CPU_POWERPC:
return (regs.gpr3, regs.gpr4, regs.gpr5, regs.gpr6, regs.gpr7, regs.gpr8)
raise NotImplementedError()
def readArguments(self, argument_values):
if self.name in SYSCALL_PROTOTYPES:
self.restype, formats = SYSCALL_PROTOTYPES[self.name]
for value, format in zip(argument_values, formats):
argtype, argname = format
self.addArgument(value=value, name=argname, type=argtype)
else:
for value in argument_values:
self.addArgument(value=value)
def exit(self):
if self.name in PREFORMAT_ARGUMENTS:
preformat = set(PREFORMAT_ARGUMENTS[self.name])
else:
preformat = set()
# Data pointed by arguments may have changed during the syscall
# e.g. uname() syscall
for index, argument in enumerate(self.arguments):
if index in preformat:
# Don't lose preformatted arguments
continue
if argument.type and not argument.type.endswith("*"):
continue
argument.text = None
self.result = self.process.getreg(RETURN_VALUE_REGISTER)
if self.restype.endswith("*"):
text = formatAddress(self.result)
else:
uresult = self.result
self.result = ulong2long(self.result)
if self.result < 0 and (-self.result) in errorcode:
errcode = -self.result
text = "%s %s (%s)" % (
self.result, errorcode[errcode], strerror(errcode))
elif not(0 <= self.result <= 9):
text = "%s (%s)" % (self.result, formatWordHex(uresult))
else:
text = str(self.result)
self.result_text = text
return text
def __str__(self):
return "" % self.name
python-ptrace-0.9.3/ptrace/syscall/freebsd_syscall.py 0000664 0001750 0001750 00000022066 13047323113 023255 0 ustar haypo haypo 0000000 0000000 # FreeBSD kernel syscall list from FreeBSD 7.0RC1 for i386
#
# List extracted from:
# /usr/include/sys/syscall.h
SYSCALL_NAMES = {
0: "syscall",
1: "exit",
2: "fork",
3: "read",
4: "write",
5: "open",
6: "close",
7: "wait4",
# 8: old creat
9: "link",
10: "unlink",
# 11: obsolete execv
12: "chdir",
13: "fchdir",
14: "mknod",
15: "chmod",
16: "chown",
17: "break",
18: "freebsd4_getfsstat",
# 19: old lseek
20: "getpid",
21: "mount",
22: "unmount",
23: "setuid",
24: "getuid",
25: "geteuid",
26: "ptrace",
27: "recvmsg",
28: "sendmsg",
29: "recvfrom",
30: "accept",
31: "getpeername",
32: "getsockname",
33: "access",
34: "chflags",
35: "fchflags",
36: "sync",
37: "kill",
# 38: old stat
39: "getppid",
# 40: old lstat
41: "dup",
42: "pipe",
43: "getegid",
44: "profil",
45: "ktrace",
# 46: old sigaction
47: "getgid",
# 48: old sigprocmask
49: "getlogin",
50: "setlogin",
51: "acct",
# 52: old sigpending
53: "sigaltstack",
54: "ioctl",
55: "reboot",
56: "revoke",
57: "symlink",
58: "readlink",
59: "execve",
60: "umask",
61: "chroot",
# 62: old fstat
# 63: old getkerninfo
# 64: old getpagesize
65: "msync",
66: "vfork",
# 67: obsolete vread
# 68: obsolete vwrite
69: "sbrk",
70: "sstk",
# 71: old mmap
72: "vadvise",
73: "munmap",
74: "mprotect",
75: "madvise",
# 76: obsolete vhangup
# 77: obsolete vlimit
78: "mincore",
79: "getgroups",
80: "setgroups",
81: "getpgrp",
82: "setpgid",
83: "setitimer",
# 84: old wait
85: "swapon",
86: "getitimer",
# 87: old gethostname
# 88: old sethostname
89: "getdtablesize",
90: "dup2",
92: "fcntl",
93: "select",
95: "fsync",
96: "setpriority",
97: "socket",
98: "connect",
# 99: old accept
100: "getpriority",
# 101: old send
# 102: old recv
# 103: old sigreturn
104: "bind",
105: "setsockopt",
106: "listen",
# 107: obsolete vtimes
# 108: old sigvec
# 109: old sigblock
# 110: old sigsetmask
# 111: old sigsuspend
# 112: old sigstack
# 113: old recvmsg
# 114: old sendmsg
# 115: obsolete vtrace
116: "gettimeofday",
117: "getrusage",
118: "getsockopt",
120: "readv",
121: "writev",
122: "settimeofday",
123: "fchown",
124: "fchmod",
# 125: old recvfrom
126: "setreuid",
127: "setregid",
128: "rename",
# 129: old truncate
# 130: old ftruncate
131: "flock",
132: "mkfifo",
133: "sendto",
134: "shutdown",
135: "socketpair",
136: "mkdir",
137: "rmdir",
138: "utimes",
# 139: obsolete 4.2 sigreturn
140: "adjtime",
# 141: old getpeername
# 142: old gethostid
# 143: old sethostid
# 144: old getrlimit
# 145: old setrlimit
# 146: old killpg
147: "setsid",
148: "quotactl",
# 149: old quota
# 150: old getsockname
155: "nfssvc",
# 156: old getdirentries
157: "freebsd4_statfs",
158: "freebsd4_fstatfs",
160: "lgetfh",
161: "getfh",
162: "getdomainname",
163: "setdomainname",
164: "uname",
165: "sysarch",
166: "rtprio",
169: "semsys",
170: "msgsys",
171: "shmsys",
173: "freebsd6_pread",
174: "freebsd6_pwrite",
176: "ntp_adjtime",
181: "setgid",
182: "setegid",
183: "seteuid",
188: "stat",
189: "fstat",
190: "lstat",
191: "pathconf",
192: "fpathconf",
194: "getrlimit",
195: "setrlimit",
196: "getdirentries",
197: "freebsd6_mmap",
198: "__syscall",
199: "freebsd6_lseek",
200: "freebsd6_truncate",
201: "freebsd6_ftruncate",
202: "__sysctl",
203: "mlock",
204: "munlock",
205: "undelete",
206: "futimes",
207: "getpgid",
209: "poll",
220: "__semctl",
221: "semget",
222: "semop",
224: "msgctl",
225: "msgget",
226: "msgsnd",
227: "msgrcv",
228: "shmat",
229: "shmctl",
230: "shmdt",
231: "shmget",
232: "clock_gettime",
233: "clock_settime",
234: "clock_getres",
235: "ktimer_create",
236: "ktimer_delete",
237: "ktimer_settime",
238: "ktimer_gettime",
239: "ktimer_getoverrun",
240: "nanosleep",
248: "ntp_gettime",
250: "minherit",
251: "rfork",
252: "openbsd_poll",
253: "issetugid",
254: "lchown",
255: "aio_read",
256: "aio_write",
257: "lio_listio",
272: "getdents",
274: "lchmod",
275: "netbsd_lchown",
276: "lutimes",
277: "netbsd_msync",
278: "nstat",
279: "nfstat",
280: "nlstat",
289: "preadv",
290: "pwritev",
297: "freebsd4_fhstatfs",
298: "fhopen",
299: "fhstat",
300: "modnext",
301: "modstat",
302: "modfnext",
303: "modfind",
304: "kldload",
305: "kldunload",
306: "kldfind",
307: "kldnext",
308: "kldstat",
309: "kldfirstmod",
310: "getsid",
311: "setresuid",
312: "setresgid",
# 313: obsolete signanosleep
314: "aio_return",
315: "aio_suspend",
316: "aio_cancel",
317: "aio_error",
318: "oaio_read",
319: "oaio_write",
320: "olio_listio",
321: "yield",
# 322: obsolete thr_sleep
# 323: obsolete thr_wakeup
324: "mlockall",
325: "munlockall",
326: "__getcwd",
327: "sched_setparam",
328: "sched_getparam",
329: "sched_setscheduler",
330: "sched_getscheduler",
331: "sched_yield",
332: "sched_get_priority_max",
333: "sched_get_priority_min",
334: "sched_rr_get_interval",
335: "utrace",
336: "freebsd4_sendfile",
337: "kldsym",
338: "jail",
340: "sigprocmask",
341: "sigsuspend",
342: "freebsd4_sigaction",
343: "sigpending",
344: "freebsd4_sigreturn",
345: "sigtimedwait",
346: "sigwaitinfo",
347: "__acl_get_file",
348: "__acl_set_file",
349: "__acl_get_fd",
350: "__acl_set_fd",
351: "__acl_delete_file",
352: "__acl_delete_fd",
353: "__acl_aclcheck_file",
354: "__acl_aclcheck_fd",
355: "extattrctl",
356: "extattr_set_file",
357: "extattr_get_file",
358: "extattr_delete_file",
359: "aio_waitcomplete",
360: "getresuid",
361: "getresgid",
362: "kqueue",
363: "kevent",
371: "extattr_set_fd",
372: "extattr_get_fd",
373: "extattr_delete_fd",
374: "__setugid",
375: "nfsclnt",
376: "eaccess",
378: "nmount",
379: "kse_exit",
380: "kse_wakeup",
381: "kse_create",
382: "kse_thr_interrupt",
383: "kse_release",
384: "__mac_get_proc",
385: "__mac_set_proc",
386: "__mac_get_fd",
387: "__mac_get_file",
388: "__mac_set_fd",
389: "__mac_set_file",
390: "kenv",
391: "lchflags",
392: "uuidgen",
393: "sendfile",
394: "mac_syscall",
395: "getfsstat",
396: "statfs",
397: "fstatfs",
398: "fhstatfs",
400: "ksem_close",
401: "ksem_post",
402: "ksem_wait",
403: "ksem_trywait",
404: "ksem_init",
405: "ksem_open",
406: "ksem_unlink",
407: "ksem_getvalue",
408: "ksem_destroy",
409: "__mac_get_pid",
410: "__mac_get_link",
411: "__mac_set_link",
412: "extattr_set_link",
413: "extattr_get_link",
414: "extattr_delete_link",
415: "__mac_execve",
416: "sigaction",
417: "sigreturn",
421: "getcontext",
422: "setcontext",
423: "swapcontext",
424: "swapoff",
425: "__acl_get_link",
426: "__acl_set_link",
427: "__acl_delete_link",
428: "__acl_aclcheck_link",
429: "sigwait",
430: "thr_create",
431: "thr_exit",
432: "thr_self",
433: "thr_kill",
434: "_umtx_lock",
435: "_umtx_unlock",
436: "jail_attach",
437: "extattr_list_fd",
438: "extattr_list_file",
439: "extattr_list_link",
440: "kse_switchin",
441: "ksem_timedwait",
442: "thr_suspend",
443: "thr_wake",
444: "kldunloadf",
445: "audit",
446: "auditon",
447: "getauid",
448: "setauid",
449: "getaudit",
450: "setaudit",
451: "getaudit_addr",
452: "setaudit_addr",
453: "auditctl",
454: "_umtx_op",
455: "thr_new",
456: "sigqueue",
457: "kmq_open",
458: "kmq_setattr",
459: "kmq_timedreceive",
460: "kmq_timedsend",
461: "kmq_notify",
462: "kmq_unlink",
463: "abort2",
464: "thr_set_name",
465: "aio_fsync",
466: "rtprio_thread",
471: "sctp_peeloff",
472: "sctp_generic_sendmsg",
473: "sctp_generic_sendmsg_iov",
474: "sctp_generic_recvmsg",
475: "pread",
476: "pwrite",
477: "mmap",
478: "lseek",
479: "truncate",
480: "ftruncate",
481: "thr_kill2",
}
SOCKET_SYSCALL_NAMES = set((
"socket", "socketpair", "connect",
"sendto", "recvfrom", "sendmsg", "recvmsg",
"bind", "listen", "accept",
"getpeername", "getsockname", "getsockopt", "setsockopt",
"shutdown",
))
python-ptrace-0.9.3/ptrace/syscall/linux_struct.py 0000664 0001750 0001750 00000002431 13047323111 022644 0 ustar haypo haypo 0000000 0000000 from ctypes import (Structure,
c_char, c_short, c_int, c_uint, c_long, c_ulong)
time_t = c_long
suseconds_t = c_long
rlim_t = c_long
class timeval(Structure):
_fields_ = (
("tv_sec", time_t),
("tv_usec", suseconds_t),
)
class timespec(Structure):
_fields_ = (
("tv_sec", time_t),
("tv_nsec", c_long),
)
class pollfd(Structure):
_fields_ = (
("fd", c_int),
("events", c_short),
("revents", c_short),
)
class rlimit(Structure):
_fields_ = (
("rlim_cur", rlim_t),
("rlim_max", rlim_t),
)
class new_utsname(Structure):
_fields_ = (
("sysname", c_char * 65),
("nodename", c_char * 65),
("release", c_char * 65),
("version", c_char * 65),
("machine", c_char * 65),
("domainname", c_char * 65),
)
# Arch depend
class user_desc(Structure):
_fields_ = (
("entry_number", c_uint),
("base_addr", c_ulong),
("limit", c_uint),
("_bits_", c_char),
# unsigned int seg_32bit:1;
# unsigned int contents:2;
# unsigned int read_exec_only:1;
# unsigned int limit_in_pages:1;
# unsigned int seg_not_present:1;
# unsigned int useable:1;
)
python-ptrace-0.9.3/ptrace/syscall/linux_constants.py 0000664 0001750 0001750 00000001424 13047323111 023335 0 ustar haypo haypo 0000000 0000000 from ptrace.syscall.posix_constants import SYSCALL_ARG_DICT
SIGSET_SIZE = 64
FD_SETSIZE = 1024
RLIMIT_RESOURCE = {
0: "RLIMIT_CPU",
1: "RLIMIT_FSIZE",
2: "RLIMIT_DATA",
3: "RLIMIT_STACK",
4: "RLIMIT_CORE",
5: "RLIMIT_RSS",
6: "RLIMIT_NPROC",
7: "RLIMIT_NOFILE",
8: "RLIMIT_MEMLOCK",
9: "RLIMIT_AS",
10: "RLIMIT_LOCKS",
11: "RLIMIT_SIGPENDING",
12: "RLIMIT_MSGQUEUE",
13: "RLIMIT_NICE",
14: "RLIMIT_RTPRIO",
15: "RLIMIT_NLIMITS",
}
SIGPROCMASK_HOW = {0: "SIG_BLOCK", 1: "SIG_UNBLOCK", 2: "SIG_SETMASK"}
SYSCALL_ARG_DICT.update({
"getrlimit": {"resource": RLIMIT_RESOURCE},
"setrlimit": {"resource": RLIMIT_RESOURCE},
"sigprocmask": {"how": SIGPROCMASK_HOW},
"rt_sigprocmask": {"how": SIGPROCMASK_HOW},
})
python-ptrace-0.9.3/ptrace/syscall/socketcall_constants.py 0000664 0001750 0001750 00000003250 13047323324 024327 0 ustar haypo haypo 0000000 0000000 import socket
SOCKETCALL = {
1: "socket",
2: "bind",
3: "connect",
4: "listen",
5: "accept",
6: "getsockname",
7: "getpeername",
8: "socketpair",
9: "send",
10: "recv",
11: "sendto",
12: "recvfrom",
13: "shutdown",
14: "setsockopt",
15: "getsockopt",
16: "sendmsg",
17: "recvmsg",
}
SOCKET_FAMILY = {
0: "AF_UNSPEC",
1: "AF_FILE",
2: "AF_INET",
3: "AF_AX25",
4: "AF_IPX",
5: "AF_APPLETALK",
6: "AF_NETROM",
7: "AF_BRIDGE",
8: "AF_ATMPVC",
9: "AF_X25",
10: "AF_INET6",
11: "AF_ROSE",
12: "AF_DECnet",
13: "AF_NETBEUI",
14: "AF_SECURITY",
15: "AF_KEY",
16: "AF_NETLINK",
17: "AF_PACKET",
18: "AF_ASH",
19: "AF_ECONET",
20: "AF_ATMSVC",
22: "AF_SNA",
23: "AF_IRDA",
24: "AF_PPPOX",
25: "AF_WANPIPE",
31: "AF_BLUETOOTH",
}
SOCKET_TYPE = {
1: "SOCK_STREAM",
2: "SOCK_DGRAM",
3: "SOCK_RAW",
4: "SOCK_RDM",
5: "SOCK_SEQPACKET",
10: "SOCK_PACKET",
}
def formatSocketType(argument):
value = argument.value
text = []
if hasattr(socket, 'SOCK_CLOEXEC'):
cloexec = value & socket.SOCK_CLOEXEC
value &= ~socket.SOCK_CLOEXEC
else:
cloexec = False
text = SOCKET_TYPE.get(value, str(value))
if cloexec:
text += '|SOCK_CLOEXEC'
return text
SOCKET_PROTOCOL = {
1: "IPPROTO_ICMP",
58: "IPPROTO_ICMPV6",
}
SETSOCKOPT_LEVEL = {
0: "SOL_IP",
1: "SOL_SOCKET",
}
SETSOCKOPT_OPTNAME = {
# level 0 (SOL_IP)
1: "IP_TOS",
# level 1 (SOL_SOCKET)
2: "SO_REUSEADDR",
9: "SO_KEEPALIVE",
20: "SO_RCVTIMEO",
21: "SO_SNDTIMEO",
}
python-ptrace-0.9.3/ptrace/debugger/ 0000775 0001750 0001750 00000000000 13160156527 017654 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/ptrace/debugger/__init__.py 0000664 0001750 0001750 00000001123 13047323111 021747 0 ustar haypo haypo 0000000 0000000 from ptrace.debugger.breakpoint import Breakpoint # noqa
from ptrace.debugger.process_event import (ProcessEvent, ProcessExit, # noqa
NewProcessEvent, ProcessExecution)
from ptrace.debugger.ptrace_signal import ProcessSignal # noqa
from ptrace.debugger.process_error import ProcessError # noqa
from ptrace.debugger.child import ChildError # noqa
from ptrace.debugger.process import PtraceProcess # noqa
from ptrace.debugger.debugger import PtraceDebugger, DebuggerError # noqa
from ptrace.debugger.application import Application # noqa
python-ptrace-0.9.3/ptrace/debugger/signal_reason.py 0000664 0001750 0001750 00000013506 13047323113 023046 0 ustar haypo haypo 0000000 0000000 from ptrace.ctypes_tools import formatAddress, formatWordHex
from ptrace.error import PtraceError
from ptrace.cpu_info import CPU_I386, CPU_X86_64
from ptrace.process_tools import formatProcessStatus
import re
# Find all Intel registers (in upper case)
if CPU_I386:
regex = 'E[A-Z]{2}|[CDEFGS]S|[ABCD]L'
elif CPU_X86_64:
regex = '[ER][A-Z]{2}|[CDEFGS]S|[ABCD]L'
else:
regex = None
if regex:
REGISTER_REGEX = re.compile(r'\b(?:%s)\b' % regex)
else:
REGISTER_REGEX = None
def extractRegisters(process, instr):
registers = {}
if not process or not instr or not REGISTER_REGEX:
return registers
asm = instr.text
asm = asm.upper()
# Skip the operator ("MOV CL, [EAX]" => "CL, [EAX]")
asm = asm.split(" ", 1)[1]
for match in REGISTER_REGEX.finditer(asm):
name = match.group(0)
name = name.lower()
try:
value = process.getreg(name)
registers[name] = value
except PtraceError:
pass
return registers
def findMappings(addresses, process, size):
mappings = []
if addresses is None or not process:
return mappings
if not isinstance(addresses, (list, tuple)):
addresses = (addresses,)
if not size:
size = 0
process_mappings = process.readMappings()
if not process_mappings:
return mappings
for address in addresses:
address_str = formatAddress(address)
if 1 < size:
address_str += "..%s" % formatAddress(address + size - 1)
found = False
for map in process_mappings:
if (map.start <= address < map.end) \
or (map.start <= (address + size - 1) < map.end):
found = True
mappings.append("%s is part of %s" % (address_str, map))
if not found:
mappings.append("%s is not mapped in memory" % address_str)
return mappings
class SignalInfo(Exception):
def __init__(self, name, text,
address=None, size=None, instr=None,
process=None, registers=None):
Exception.__init__(self, text)
self.name = name
self.text = text
self.instr = instr
self.registers = extractRegisters(process, instr)
if registers:
self.registers.update(registers)
self.mappings = findMappings(address, process, size)
def display(self, log):
log(self.text)
self.displayExtra(log)
if self.instr:
log("- instruction: %s" % self.instr)
for mapping in self.mappings:
log("- mapping: %s" % mapping)
for name, value in self.registers.items():
log("- register %s=%s" % (name, formatWordHex(value)))
def displayExtra(self, log):
pass
class DivisionByZero(SignalInfo):
def __init__(self, instr=None, process=None):
SignalInfo.__init__(self, "div_by_zero",
"Division by zero", instr=instr, process=process)
class Abort(SignalInfo):
def __init__(self):
SignalInfo.__init__(self, "abort",
"Program received signal SIGABRT, Aborted.")
class StackOverflow(SignalInfo):
def __init__(self, stack_ptr, stack_map, instr=None, process=None):
text = "STACK OVERFLOW! Stack pointer is in %s" % stack_map
SignalInfo.__init__(self, "stack_overflow", text,
address=stack_ptr, registers={
'': stack_ptr},
instr=instr, process=process)
self.stack_ptr = stack_ptr
self.stack_map = stack_map
class InvalidMemoryAccess(SignalInfo):
NAME = "invalid_mem_access"
PREFIX = "Invalid memory access"
PREFIX_ADDR = "Invalid memory access to %s"
def __init__(self, address=None, size=None, instr=None, registers=None, process=None):
"""
address is an integer or a list of integer
"""
if address is not None:
if isinstance(address, (list, tuple)):
arguments = " or ".join(formatAddress(addr)
for addr in address)
else:
arguments = formatAddress(address)
message = self.PREFIX_ADDR % arguments
else:
message = self.PREFIX
if size:
message += " (size=%s bytes)" % size
name = self.NAME
if address is not None:
name += "-" + formatAddress(address).lower()
SignalInfo.__init__(self, name, message,
address=address, size=size, instr=instr,
process=process, registers=registers)
class InvalidRead(InvalidMemoryAccess):
NAME = "invalid_read"
PREFIX = "Invalid read"
PREFIX_ADDR = "Invalid read from %s"
class InvalidWrite(InvalidMemoryAccess):
NAME = "invalid_write"
PREFIX = "Invalid write"
PREFIX_ADDR = "Invalid write to %s"
class InstructionError(SignalInfo):
def __init__(self, address, process=None):
SignalInfo.__init__(self, "instr_error",
"UNABLE TO EXECUTE CODE AT %s (SEGMENTATION FAULT)" % formatAddress(
address),
address=address,
process=process,
registers={'': address})
class ChildExit(SignalInfo):
def __init__(self, pid=None, status=None, uid=None):
if pid is not None and status is not None:
message = formatProcessStatus(status, "Child process %s" % pid)
else:
message = "Child process exited"
SignalInfo.__init__(self, "child_exit", message)
self.pid = pid
self.status = status
self.uid = uid
def displayExtra(self, log):
if self.uid is not None:
log("Signal sent by user %s" % self.uid)
python-ptrace-0.9.3/ptrace/debugger/process.py 0000664 0001750 0001750 00000062427 13053016452 021710 0 ustar haypo haypo 0000000 0000000 from ptrace.binding import (
HAS_PTRACE_SINGLESTEP, HAS_PTRACE_EVENTS,
HAS_PTRACE_SIGINFO, HAS_PTRACE_IO, HAS_PTRACE_GETREGS,
ptrace_attach, ptrace_detach,
ptrace_cont, ptrace_syscall,
ptrace_setregs,
ptrace_peektext, ptrace_poketext,
REGISTER_NAMES)
from ptrace.os_tools import HAS_PROC, RUNNING_BSD, RUNNING_PYTHON3
from ptrace.tools import dumpRegs
from ptrace.cpu_info import CPU_WORD_SIZE
from ptrace.ctypes_tools import bytes2word, word2bytes, bytes2type, bytes2array
from signal import SIGTRAP, SIGSTOP, SIGKILL
from ptrace.ctypes_tools import formatAddress, formatWordHex
from ctypes import sizeof, c_char_p
from logging import info, warning, error
from ptrace.error import PtraceError
from errno import ESRCH, EACCES
from ptrace.debugger import (Breakpoint,
ProcessExit, ProcessSignal, NewProcessEvent, ProcessExecution)
from os import (kill,
WIFSTOPPED, WSTOPSIG,
WIFSIGNALED, WTERMSIG,
WIFEXITED, WEXITSTATUS)
from ptrace.disasm import HAS_DISASSEMBLER
from ptrace.debugger.backtrace import getBacktrace
from ptrace.debugger.process_error import ProcessError
from ptrace.debugger.memory_mapping import readProcessMappings
from ptrace.binding.cpu import CPU_INSTR_POINTER, CPU_STACK_POINTER, CPU_FRAME_POINTER, CPU_SUB_REGISTERS
from ptrace.debugger.syscall_state import SyscallState
from ptrace.six import b
if HAS_PTRACE_SINGLESTEP:
from ptrace.binding import ptrace_singlestep
if HAS_PTRACE_SIGINFO:
from ptrace.binding import ptrace_getsiginfo
if HAS_PTRACE_IO:
from ctypes import create_string_buffer, addressof
from ptrace.binding import (
ptrace_io, ptrace_io_desc,
PIOD_READ_D, PIOD_WRITE_D)
if HAS_PTRACE_EVENTS:
from ptrace.binding import (
ptrace_setoptions, ptrace_geteventmsg, WPTRACEEVENT,
PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK, PTRACE_EVENT_CLONE,
PTRACE_EVENT_EXEC)
NEW_PROCESS_EVENT = (
PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK, PTRACE_EVENT_CLONE)
if HAS_PTRACE_GETREGS:
from ptrace.binding import ptrace_getregs
else:
from ptrace.binding import ptrace_peekuser, ptrace_registers_t
if HAS_DISASSEMBLER:
from ptrace.disasm import disassemble, disassembleOne, MAX_INSTR_SIZE
if HAS_PROC:
from ptrace.linux_proc import readProcessStat
MIN_CODE_SIZE = 32
MAX_CODE_SIZE = 1024
DEFAULT_NB_INSTR = 10
DEFAULT_CODE_SIZE = 24
class PtraceProcess(object):
"""
Process traced by a PtraceDebugger.
Methods
=======
* control execution:
- singleStep(): execute one instruction
- cont(): continue the execution
- syscall(): break at next syscall
- setInstrPointer(): change the instruction pointer
- kill(): send a signal to the process
- terminate(): kill the process
* wait an event:
- waitEvent(): wait next process event
- waitSignals(): wait a signal
* get status
- getreg(): get a register
- getInstrPointer(): get the instruction pointer
- getStackPointer(): get the stack pointer
- getFramePointer(): get the stack pointer
- getregs(): get all registers, e.g. regs=getregs(); print regs.eax
- disassemble(): assembler code of the next instructions
- disassembleOne(): assembler code of the next instruction
- findStack(): get stack memory mapping
- getsiginfo(): get signal information
- getBacktrace(): get the current backtrace
* set status
- setreg(): set a register
- setregs(): set all registers
* memory access:
- readWord(): read a memory word
- readBytes(): read some bytes
- readStruct(): read a structure
- readArray(): read an array
- readCString(): read a C string
- readMappings(): get all memory mappings
- writeWord(): write a memory word
- writeBytes(): write some bytes
* display status:
- dumpCore(): display the next instructions
- dumpStack(): display some memory words around the stack pointer
- dumpMaps(): display memory mappings
- dumpRegs(): display all registers
* breakpoint:
- createBreakpoint(): set a breakpoint
- findBreakpoint(): find a breakpoint
- removeBreakpoint(): remove a breakpoint
* other:
- setoptions(): set ptrace options
See each method to get better documentation. You are responsible
to manage the process state: some methods may fail or crash your
processus if they are called when the process is in the wrong
state.
Attributes
==========
* main attributes:
- pid: identifier of the process
- debugger: PtraceDebugger instance
- breakpoints: dictionary of active breakpoints
- parent: parent PtraceProcess (None if process has no parent)
* state:
- running: if True, the process is alive, otherwise the process
doesn't exist anymore
- exited: if True, the process has exited (attributed only used
on BSD operation systems)
- is_attached: if True, the process is attached by ptrace
- was_attached: if True, the process will be detached at exit
- is_stopped: if True, the process is stopped, otherwise it's
running
- syscall_state: control syscall tracing
Sometimes, is_stopped value is wrong. You might use isTraced() to
make sure that the process is stopped.
"""
def __init__(self, debugger, pid, is_attached, parent=None, is_thread=False):
self.debugger = debugger
self.breakpoints = {}
self.pid = pid
self.running = True
self.exited = False
self.parent = parent
self.was_attached = is_attached
self.is_attached = False
self.is_stopped = True
self.is_thread = is_thread
if not is_attached:
self.attach()
else:
self.is_attached = True
if HAS_PROC:
self.read_mem_file = None
self.syscall_state = SyscallState(self)
def isTraced(self):
if not HAS_PROC:
self.notImplementedError()
stat = readProcessStat(self.pid)
return (stat.state == 'T')
def attach(self):
if self.is_attached:
return
info("Attach process %s" % self.pid)
ptrace_attach(self.pid)
self.is_attached = True
def dumpCode(self, start=None, stop=None, manage_bp=False, log=None):
if not log:
log = error
try:
ip = self.getInstrPointer()
except PtraceError as err:
if start is None:
log("Unable to read instruction pointer: %s" % err)
return
ip = None
if start is None:
start = ip
try:
self._dumpCode(start, stop, ip, manage_bp, log)
except PtraceError as err:
log("Unable to dump code at %s: %s" % (
formatAddress(start), err))
def _dumpCode(self, start, stop, ip, manage_bp, log):
if stop is not None:
stop = max(start, stop)
stop = min(stop, start + MAX_CODE_SIZE - 1)
if not HAS_DISASSEMBLER:
if stop is not None:
size = stop - start + 1
else:
size = MIN_CODE_SIZE
code = self.readBytes(start, size)
if RUNNING_PYTHON3:
text = " ".join("%02x" % byte for byte in code)
else:
text = " ".join("%02x" % ord(byte) for byte in code)
log("CODE: %s" % text)
return
if manage_bp:
address = start
for line in range(10):
bp = False
if address in self.breakpoints:
bytes = self.breakpoints[address].old_bytes
instr = disassembleOne(bytes, address)
bp = True
else:
instr = self.disassembleOne(address)
text = "%s| %s (%s)" % (formatAddress(
instr.address), instr.text, instr.hexa)
if instr.address == ip:
text += " <=="
if bp:
text += " * BREAKPOINT *"
log(text)
address = address + instr.size
if stop is not None and stop <= address:
break
else:
for instr in self.disassemble(start, stop):
text = "%s| %s (%s)" % (formatAddress(
instr.address), instr.text, instr.hexa)
if instr.address == ip:
text += " <=="
log(text)
def disassemble(self, start=None, stop=None, nb_instr=None):
if not HAS_DISASSEMBLER:
self.notImplementedError()
if start is None:
start = self.getInstrPointer()
if stop is not None:
stop = max(start, stop)
size = stop - start + 1
else:
if nb_instr is None:
nb_instr = DEFAULT_NB_INSTR
size = nb_instr * MAX_INSTR_SIZE
code = self.readBytes(start, size)
for index, instr in enumerate(disassemble(code, start)):
yield instr
if nb_instr and nb_instr <= (index + 1):
break
def disassembleOne(self, address=None):
if not HAS_DISASSEMBLER:
self.notImplementedError()
if address is None:
address = self.getInstrPointer()
code = self.readBytes(address, MAX_INSTR_SIZE)
return disassembleOne(code, address)
def findStack(self):
for map in self.readMappings():
if map.pathname == "[stack]":
return map
return None
def detach(self):
if not self.is_attached:
return
self.is_attached = False
if self.running:
if self.was_attached:
info("Detach %s" % self)
ptrace_detach(self.pid)
elif self.is_stopped:
info("Continue process %s execution" % self.pid)
self.cont()
self.debugger.deleteProcess(process=self)
def _notRunning(self):
self.running = False
if HAS_PROC and self.read_mem_file:
try:
self.read_mem_file.close()
except IOError:
pass
self.detach()
def kill(self, signum):
kill(self.pid, signum)
def terminate(self, wait_exit=True):
if not self.running or not self.was_attached:
return True
warning("Terminate %s" % self)
done = False
try:
if self.is_stopped:
self.cont(SIGKILL)
else:
self.kill(SIGKILL)
except PtraceError as event:
if event.errno == ESRCH:
done = True
else:
raise event
if not done:
if not wait_exit:
return False
self.waitExit()
self._notRunning()
return True
def waitExit(self):
while True:
# Wait for any process signal
event = self.waitEvent()
event_cls = event.__class__
# Process exited: we are done
if event_cls == ProcessExit:
return
# Event different than a signal? Raise an exception
if event_cls != ProcessSignal:
raise event
# Send the signal to the process
signum = event.signum
if signum not in (SIGTRAP, SIGSTOP):
self.cont(signum)
else:
self.cont()
def processStatus(self, status):
# Process exited?
if WIFEXITED(status):
code = WEXITSTATUS(status)
event = self.processExited(code)
# Process killed by a signal?
elif WIFSIGNALED(status):
signum = WTERMSIG(status)
event = self.processKilled(signum)
# Invalid process status?
elif not WIFSTOPPED(status):
raise ProcessError(self, "Unknown process status: %r" % status)
# Ptrace event?
elif HAS_PTRACE_EVENTS and WPTRACEEVENT(status):
event = WPTRACEEVENT(status)
event = self.ptraceEvent(event)
else:
signum = WSTOPSIG(status)
event = self.processSignal(signum)
return event
def processTerminated(self):
self._notRunning()
return ProcessExit(self)
def processExited(self, code):
if RUNNING_BSD and not self.exited:
# on FreeBSD, we have to waitpid() twice
# to avoid zombi process!?
self.exited = True
self.waitExit()
self._notRunning()
return ProcessExit(self, exitcode=code)
def processKilled(self, signum):
self._notRunning()
return ProcessExit(self, signum=signum)
def processSignal(self, signum):
self.is_stopped = True
return ProcessSignal(signum, self)
def ptraceEvent(self, event):
if not HAS_PTRACE_EVENTS:
self.notImplementedError()
if event in NEW_PROCESS_EVENT:
new_pid = ptrace_geteventmsg(self.pid)
is_thread = (event == PTRACE_EVENT_CLONE)
new_process = self.debugger.addProcess(
new_pid, is_attached=True, parent=self, is_thread=is_thread)
return NewProcessEvent(new_process)
elif event == PTRACE_EVENT_EXEC:
return ProcessExecution(self)
else:
raise ProcessError(self, "Unknown ptrace event: %r" % event)
def getregs(self):
if HAS_PTRACE_GETREGS:
return ptrace_getregs(self.pid)
else:
# FIXME: Optimize getreg() when used with this function
words = []
nb_words = sizeof(ptrace_registers_t) // CPU_WORD_SIZE
for offset in range(nb_words):
word = ptrace_peekuser(self.pid, offset * CPU_WORD_SIZE)
bytes = word2bytes(word)
words.append(bytes)
bytes = ''.join(words)
return bytes2type(bytes, ptrace_registers_t)
def getreg(self, name):
try:
name, shift, mask = CPU_SUB_REGISTERS[name]
except KeyError:
shift = 0
mask = None
if name not in REGISTER_NAMES:
raise ProcessError(self, "Unknown register: %r" % name)
regs = self.getregs()
value = getattr(regs, name)
value >>= shift
if mask:
value &= mask
return value
def setregs(self, regs):
ptrace_setregs(self.pid, regs)
def setreg(self, name, value):
regs = self.getregs()
if name in CPU_SUB_REGISTERS:
full_name, shift, mask = CPU_SUB_REGISTERS[name]
full_value = getattr(regs, full_name)
full_value &= ~mask
full_value |= ((value & mask) << shift)
value = full_value
name = full_name
if name not in REGISTER_NAMES:
raise ProcessError(self, "Unknown register: %r" % name)
setattr(regs, name, value)
self.setregs(regs)
def singleStep(self):
if not HAS_PTRACE_SINGLESTEP:
self.notImplementedError()
ptrace_singlestep(self.pid)
def filterSignal(self, signum):
if signum == SIGTRAP:
# Never transfer SIGTRAP signal
return 0
else:
return signum
def syscall(self, signum=0):
signum = self.filterSignal(signum)
ptrace_syscall(self.pid, signum)
self.is_stopped = False
def setInstrPointer(self, ip):
if CPU_INSTR_POINTER:
self.setreg(CPU_INSTR_POINTER, ip)
else:
raise ProcessError(
self, "Instruction pointer register is not defined")
def getInstrPointer(self):
if CPU_INSTR_POINTER:
return self.getreg(CPU_INSTR_POINTER)
else:
raise ProcessError(
self, "Instruction pointer register is not defined")
def getStackPointer(self):
if CPU_STACK_POINTER:
return self.getreg(CPU_STACK_POINTER)
else:
raise ProcessError(self, "Stack pointer register is not defined")
def getFramePointer(self):
if CPU_FRAME_POINTER:
return self.getreg(CPU_FRAME_POINTER)
else:
raise ProcessError(self, "Stack pointer register is not defined")
def _readBytes(self, address, size):
offset = address % CPU_WORD_SIZE
if offset:
# Read word
address -= offset
word = self.readWord(address)
bytes = word2bytes(word)
# Read some bytes from the word
subsize = min(CPU_WORD_SIZE - offset, size)
data = bytes[offset:offset + subsize] # <-- FIXME: Big endian!
# Move cursor
size -= subsize
address += CPU_WORD_SIZE
else:
data = b('')
while size:
# Read word
word = self.readWord(address)
bytes = word2bytes(word)
# Read bytes from the word
if size < CPU_WORD_SIZE:
data += bytes[:size] # <-- FIXME: Big endian!
break
data += bytes
# Move cursor
size -= CPU_WORD_SIZE
address += CPU_WORD_SIZE
return data
def readWord(self, address):
"""Address have to be aligned!"""
word = ptrace_peektext(self.pid, address)
return word
if HAS_PTRACE_IO:
def readBytes(self, address, size):
buffer = create_string_buffer(size)
io_desc = ptrace_io_desc(
piod_op=PIOD_READ_D,
piod_offs=address,
piod_addr=addressof(buffer),
piod_len=size)
ptrace_io(self.pid, io_desc)
return buffer.raw
elif HAS_PROC:
def readBytes(self, address, size):
if not self.read_mem_file:
filename = '/proc/%u/mem' % self.pid
try:
self.read_mem_file = open(filename, 'rb', 0)
except IOError as err:
message = "Unable to open %s: fallback to ptrace implementation" % filename
if err.errno != EACCES:
error(message)
else:
info(message)
self.readBytes = self._readBytes
return self.readBytes(address, size)
try:
mem = self.read_mem_file
mem.seek(address)
data = mem.read(size)
except (IOError, ValueError) as err:
raise ProcessError(self, "readBytes(%s, %s) error: %s" % (
formatAddress(address), size, err))
if len(data) == 0 and size:
# Issue #10: If the process was not created by the debugger
# (ex: fork), the kernel may deny reading private mappings of
# /proc/pid/mem to the debugger, depending on the kernel
# version and kernel config (ex: SELinux enabled or not).
#
# Fallback to PTRACE_PEEKTEXT. It is slower but a debugger
# tracing the process is always allowed to use it.
self.readBytes = self._readBytes
return self.readBytes(address, size)
return data
else:
readBytes = _readBytes
def getsiginfo(self):
if not HAS_PTRACE_SIGINFO:
self.notImplementedError()
return ptrace_getsiginfo(self.pid)
def writeBytes(self, address, bytes):
if HAS_PTRACE_IO:
size = len(bytes)
bytes = create_string_buffer(bytes)
io_desc = ptrace_io_desc(
piod_op=PIOD_WRITE_D,
piod_offs=address,
piod_addr=addressof(bytes),
piod_len=size)
ptrace_io(self.pid, io_desc)
else:
offset = address % CPU_WORD_SIZE
if offset:
# Write partial word (end)
address -= offset
size = CPU_WORD_SIZE - offset
word = self.readBytes(address, CPU_WORD_SIZE)
if len(bytes) < size:
size = len(bytes)
word = word[:offset] + bytes[:size] + \
word[offset + size:] # <-- FIXME: Big endian!
else:
# <-- FIXME: Big endian!
word = word[:offset] + bytes[:size]
self.writeWord(address, bytes2word(word))
bytes = bytes[size:]
address += CPU_WORD_SIZE
# Write full words
while CPU_WORD_SIZE <= len(bytes):
# Read one word
word = bytes[:CPU_WORD_SIZE]
word = bytes2word(word)
self.writeWord(address, word)
# Move to next word
bytes = bytes[CPU_WORD_SIZE:]
address += CPU_WORD_SIZE
if not bytes:
return
# Write partial word (begin)
size = len(bytes)
word = self.readBytes(address, CPU_WORD_SIZE)
# FIXME: Write big endian version of the next line
word = bytes + word[size:]
self.writeWord(address, bytes2word(word))
def readStruct(self, address, struct):
bytes = self.readBytes(address, sizeof(struct))
bytes = c_char_p(bytes)
return bytes2type(bytes, struct)
def readArray(self, address, basetype, count):
bytes = self.readBytes(address, sizeof(basetype) * count)
bytes = c_char_p(bytes)
return bytes2array(bytes, basetype, count)
def readCString(self, address, max_size, chunk_length=256):
string = []
size = 0
truncated = False
while True:
done = False
data = self.readBytes(address, chunk_length)
pos = data.find(b('\0'))
if pos != -1:
done = True
data = data[:pos]
if max_size <= size + chunk_length:
data = data[:(max_size - size)]
string.append(data)
truncated = True
break
string.append(data)
if done:
break
size += chunk_length
address += chunk_length
return b''.join(string), truncated
def dumpStack(self, log=None):
if not log:
log = error
stack = self.findStack()
if stack:
log("STACK: %s" % stack)
self._dumpStack(log)
def _dumpStack(self, log):
sp = self.getStackPointer()
displayed = 0
for index in range(-5, 5 + 1):
delta = index * CPU_WORD_SIZE
try:
value = self.readWord(sp + delta)
log("STACK%+ 3i: %s" % (delta, formatWordHex(value)))
displayed += 1
except PtraceError:
pass
if not displayed:
log("ERROR: unable to read the stack (SP=%s)" % formatAddress(sp))
def readMappings(self):
return readProcessMappings(self)
def dumpMaps(self, log=None):
if not log:
log = error
for map in self.readMappings():
log("MAPS: %s" % map)
def writeWord(self, address, word):
"""
Address have to be aligned!
"""
ptrace_poketext(self.pid, address, word)
def dumpRegs(self, log=None):
if not log:
log = error
try:
regs = self.getregs()
dumpRegs(log, regs)
except PtraceError as err:
log("Unable to read registers: %s" % err)
def cont(self, signum=0):
signum = self.filterSignal(signum)
ptrace_cont(self.pid, signum)
self.is_stopped = False
def setoptions(self, options):
if not HAS_PTRACE_EVENTS:
self.notImplementedError()
info("Set %s options to %s" % (self, options))
ptrace_setoptions(self.pid, options)
def waitEvent(self):
return self.debugger.waitProcessEvent(pid=self.pid)
def waitSignals(self, *signals):
return self.debugger.waitSignals(*signals, **{'pid': self.pid})
def waitSyscall(self):
self.debugger.waitSyscall(self)
def findBreakpoint(self, address):
for bp in self.breakpoints.values():
if bp.address <= address < bp.address + bp.size:
return bp
return None
def createBreakpoint(self, address, size=1):
bp = self.findBreakpoint(address)
if bp:
raise ProcessError(self, "A breakpoint is already set: %s" % bp)
bp = Breakpoint(self, address, size)
self.breakpoints[address] = bp
return bp
def getBacktrace(self, max_args=6, max_depth=20):
return getBacktrace(self, max_args=max_args, max_depth=max_depth)
def removeBreakpoint(self, breakpoint):
del self.breakpoints[breakpoint.address]
def __del__(self):
try:
self.detach()
except PtraceError:
pass
def __str__(self):
return self.__repr__()
def __repr__(self):
return "" % self.pid
def __hash__(self):
return hash(self.pid)
def notImplementedError(self):
raise NotImplementedError()
python-ptrace-0.9.3/ptrace/debugger/debugger.py 0000664 0001750 0001750 00000023012 13047323111 021775 0 ustar haypo haypo 0000000 0000000 from logging import info, warning, error
from ptrace import PtraceError
from os import waitpid, WNOHANG
from signal import SIGTRAP, SIGSTOP
from errno import ECHILD
from ptrace.debugger import PtraceProcess, ProcessSignal
from ptrace.binding import HAS_PTRACE_EVENTS
from time import sleep
if HAS_PTRACE_EVENTS:
from ptrace.binding.func import (
PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK,
PTRACE_O_TRACEEXEC, PTRACE_O_TRACESYSGOOD,
PTRACE_O_TRACECLONE, THREAD_TRACE_FLAGS)
class DebuggerError(PtraceError):
pass
class PtraceDebugger(object):
"""
Debugger managing one or multiple processes at the same time.
Methods
=======
* Process list:
- addProcess(): add a new process
- deleteProcess(): remove a process from the debugger
* Wait for an event:
- waitProcessEvent(): wait for a process event
- waitSignals(): wait for a signal
- waitSyscall(): wait for the next syscall event
* Options:
- traceForks(): enable fork tracing
- traceExec(): enable exec() tracing
- enableSysgood(): enable sysgood option
* Other:
- quit(): quit the debugger, terminate all processes
Operations
==========
- iterate on all processes: "for process in debugger: ..."
- get a process by its identifier: "process = debugger[pid]"
- get the number of processes: len(debugger)
Attributes
==========
- dict: processes dictionary (pid -> PtraceProcess)
- list: processes list
- options: ptrace options
- trace_fork (bool): fork() tracing is enabled?
- trace_exec (bool): exec() tracing is enabled?
- use_sysgood (bool): sysgood option is enabled?
"""
def __init__(self):
self.dict = {} # pid -> PtraceProcess object
self.list = []
self.options = 0
self.trace_fork = False
self.trace_exec = False
self.trace_clone = False
self.use_sysgood = False
self.enableSysgood()
def addProcess(self, pid, is_attached, parent=None, is_thread=False):
"""
Add a new process using its identifier. Use is_attached=False to
attach an existing (running) process, and is_attached=True to trace
a new (stopped) process.
"""
if pid in self.dict:
raise KeyError("The process %s is already registered!" % pid)
process = PtraceProcess(self, pid, is_attached,
parent=parent, is_thread=is_thread)
info("Attach %s to debugger" % process)
self.dict[pid] = process
self.list.append(process)
try:
process.waitSignals(SIGTRAP, SIGSTOP)
except KeyboardInterrupt:
error(
"User interrupt! Force the process %s attach "
"(don't wait for signals)."
% pid)
except ProcessSignal as event:
event.display()
except:
process.is_attached = False
process.detach()
raise
if HAS_PTRACE_EVENTS and self.options:
process.setoptions(self.options)
return process
def quit(self):
"""
Quit the debugger: terminate all processes in reverse order.
"""
info("Quit debugger")
# Terminate processes in reverse order
# to kill children before parents
processes = list(self.list)
for process in reversed(processes):
process.terminate()
process.detach()
def _waitpid(self, wanted_pid, blocking=True):
"""
Wait for a process event from a specific process (if wanted_pid is
set) or any process (wanted_pid=None). The call is blocking is
blocking option is True. Return the tuple (pid, status).
See os.waitpid() documentation for explanations about the result.
"""
flags = 0
if not blocking:
flags |= WNOHANG
if wanted_pid:
if wanted_pid not in self.dict:
raise DebuggerError("Unknown PID: %r" %
wanted_pid, pid=wanted_pid)
process = self.dict[wanted_pid]
if process.is_thread:
flags |= THREAD_TRACE_FLAGS
pid, status = waitpid(wanted_pid, flags)
else:
pid, status = waitpid(-1, flags)
if (blocking or pid) and wanted_pid and (pid != wanted_pid):
raise DebuggerError("Unwanted PID: %r (instead of %s)"
% (pid, wanted_pid), pid=pid)
return pid, status
def _wait_event_pid(self, wanted_pid, blocking=True):
"""
Wait for a process event from the specified process identifier. If
blocking=False, return None if there is no new event, otherwise return
an object based on ProcessEvent.
"""
process = None
while not process:
try:
pid, status = self._waitpid(wanted_pid, blocking)
except OSError as err:
if err.errno == ECHILD:
process = self.dict[wanted_pid]
return process.processTerminated()
else:
raise err
if not blocking and not pid:
return None
try:
process = self.dict[pid]
except KeyError:
warning("waitpid() warning: Unknown PID %r" % pid)
return process.processStatus(status)
def _wait_event(self, wanted_pid, blocking=True):
if wanted_pid is not None:
return self._wait_event_pid(wanted_pid, blocking)
pause = 0.001
while True:
pids = tuple(self.dict)
if len(pids) > 1:
for pid in pids:
process = self._wait_event_pid(pid, False)
if process is not None:
return process
if not blocking:
return None
pause = min(pause * 2, 0.5)
sleep(pause)
else:
return self._wait_event_pid(pids[0], blocking)
def waitProcessEvent(self, pid=None, blocking=True):
"""
Wait for a process event from a specific process (if pid option is
set) or any process (default). If blocking=False, return None if there
is no new event, otherwise return an object based on ProcessEvent.
"""
return self._wait_event(pid, blocking)
def waitSignals(self, *signals, **kw):
"""
Wait for any signal or some specific signals (if specified) from a
specific process (if pid keyword is set) or any process (default).
Return a ProcessSignal object or raise an unexpected ProcessEvent.
"""
pid = kw.get('pid', None)
while True:
event = self._wait_event(pid)
if event.__class__ != ProcessSignal:
raise event
signum = event.signum
if signum in signals or not signals:
return event
raise event
def waitSyscall(self, process=None):
"""
Wait for the next syscall event (enter or exit) for a specific process
(if specified) or any process (default). Return a ProcessSignal object
or raise an unexpected ProcessEvent.
"""
signum = SIGTRAP
if self.use_sysgood:
signum |= 0x80
if process:
return self.waitSignals(signum, pid=process.pid)
else:
return self.waitSignals(signum)
def deleteProcess(self, process=None, pid=None):
"""
Delete a process from the process list.
"""
if not process:
try:
process = self.dict[pid]
except KeyError:
return
try:
del self.dict[process.pid]
except KeyError:
pass
try:
self.list.remove(process)
except ValueError:
pass
def traceFork(self):
"""
Enable fork() tracing. Do nothing if it's not supported.
"""
if not HAS_PTRACE_EVENTS:
raise DebuggerError(
"Tracing fork events is not supported on this architecture or operating system")
self.options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
self.trace_fork = True
info("Debugger trace forks (options=%s)" % self.options)
def traceExec(self):
"""
Enable exec() tracing. Do nothing if it's not supported.
"""
if not HAS_PTRACE_EVENTS:
# no effect on OS without ptrace events
return
self.trace_exec = True
self.options |= PTRACE_O_TRACEEXEC
def traceClone(self):
"""
Enable clone() tracing. Do nothing if it's not supported.
"""
if not HAS_PTRACE_EVENTS:
# no effect on OS without ptrace events
return
self.trace_clone = True
self.options |= PTRACE_O_TRACECLONE
def enableSysgood(self):
"""
Enable sysgood option: ask the kernel to set bit #7 of the signal
number if the signal comes from the kernel space. If the signal comes
from the user space, the bit is unset.
"""
if not HAS_PTRACE_EVENTS:
# no effect on OS without ptrace events
return
self.use_sysgood = True
self.options |= PTRACE_O_TRACESYSGOOD
def __getitem__(self, pid):
return self.dict[pid]
def __iter__(self):
return iter(self.list)
def __len__(self):
return len(self.list)
python-ptrace-0.9.3/ptrace/debugger/breakpoint.py 0000664 0001750 0001750 00000003704 13047323111 022355 0 ustar haypo haypo 0000000 0000000 from ptrace.ctypes_tools import formatAddress
from ptrace import PtraceError
from logging import info
from weakref import ref
from ptrace.cpu_info import CPU_POWERPC, CPU_WORD_SIZE
from ptrace.ctypes_tools import word2bytes
from ptrace.six import b
class Breakpoint(object):
"""
Software breakpoint.
Use desinstall() method to remove the breakpoint from the process.
"""
def __init__(self, process, address, size=None):
self._installed = False
self.process = ref(process)
self.address = address
if CPU_POWERPC:
size = CPU_WORD_SIZE
elif size is None:
size = 1
self.size = size
# Store instruction bytes
info("Install %s" % self)
self.old_bytes = process.readBytes(address, size)
if CPU_POWERPC:
# Replace instruction with "TRAP"
new_bytes = word2bytes(0x0cc00000)
else:
# Replace instruction with "INT 3"
new_bytes = b("\xCC") * size
process.writeBytes(address, new_bytes)
self._installed = True
def desinstall(self, set_ip=False):
"""
Remove the breakpoint from the associated process. If set_ip is True,
restore the instruction pointer to the address of the breakpoint.
"""
if not self._installed:
return
self._installed = False
info("Desinstall %s" % self)
process = self.process()
if not process:
return
if process.running:
process.writeBytes(self.address, self.old_bytes)
if set_ip:
process.setInstrPointer(self.address)
process.removeBreakpoint(self)
def __str__(self):
return "" % (
formatAddress(self.address),
formatAddress(self.address + self.size - 1))
def __del__(self):
try:
self.desinstall(False)
except PtraceError:
pass
python-ptrace-0.9.3/ptrace/debugger/syscall_state.py 0000664 0001750 0001750 00000002557 13047323111 023076 0 ustar haypo haypo 0000000 0000000 from ptrace.syscall import PtraceSyscall
from signal import SIGTRAP
class SyscallState(object):
def __init__(self, process):
self.process = process
self.ignore_exec_trap = True
self.ignore_callback = None
self.clear()
def event(self, options):
if self.next_event == "exit":
return self.exit()
else:
return self.enter(options)
def enter(self, options):
# syscall enter
regs = self.process.getregs()
self.syscall = PtraceSyscall(self.process, options, regs)
self.name = self.syscall.name
if (not self.ignore_callback) \
or (not self.ignore_callback(self.syscall)):
self.syscall.enter(regs)
else:
self.syscall = None
self.next_event = "exit"
return self.syscall
def exit(self):
if self.syscall:
self.syscall.exit()
if self.ignore_exec_trap \
and self.name == "execve" \
and not self.process.debugger.trace_exec:
# Ignore the SIGTRAP after exec() syscall exit
self.process.syscall()
self.process.waitSignals(SIGTRAP)
syscall = self.syscall
self.clear()
return syscall
def clear(self):
self.syscall = None
self.name = None
self.next_event = "enter"
python-ptrace-0.9.3/ptrace/debugger/process_event.py 0000664 0001750 0001750 00000003534 13047323113 023101 0 ustar haypo haypo 0000000 0000000 from ptrace.signames import signalName
class ProcessEvent(Exception):
"""
A process event: program exit, program killed by a signal, program
received a signal, etc.
The attribute "process" contains the related process.
"""
def __init__(self, process, message):
Exception.__init__(self, message)
self.process = process
class ProcessExit(ProcessEvent):
"""
Process exit event:
- process kill by a signal (if signum attribute is not None)
- process exited with a code (if exitcode attribute is not None)
- process terminated abnormally (otherwise)
"""
def __init__(self, process, signum=None, exitcode=None):
pid = process.pid
if signum:
message = "Process %s killed by signal %s" % (
pid, signalName(signum))
elif exitcode is not None:
if not exitcode:
message = "Process %s exited normally" % pid
else:
message = "Process %s exited with code %s" % (pid, exitcode)
else:
message = "Process %s terminated abnormally" % pid
ProcessEvent.__init__(self, process, message)
self.signum = signum
self.exitcode = exitcode
class ProcessExecution(ProcessEvent):
"""
Process execution: event send just after the process calls the exec()
syscall if exec() tracing option is enabled.
"""
def __init__(self, process):
ProcessEvent.__init__(
self, process, "Process %s execution" % process.pid)
class NewProcessEvent(ProcessEvent):
"""
New process: event send when a process calls the fork() syscall if fork()
tracing option is enabled. The attribute process contains the new child
process.
"""
def __init__(self, process):
ProcessEvent.__init__(self, process, "New process %s" % process.pid)
python-ptrace-0.9.3/ptrace/debugger/application.py 0000664 0001750 0001750 00000006442 13047323113 022526 0 ustar haypo haypo 0000000 0000000 from optparse import OptionGroup
from logging import (getLogger, StreamHandler,
DEBUG, INFO, WARNING, ERROR)
from sys import exit
from ptrace import PtraceError
from logging import error
from ptrace.tools import locateProgram
from ptrace.debugger import ProcessExit, DebuggerError
from errno import EPERM
from ptrace.debugger.child import createChild
class Application(object):
def __init__(self):
pass
def _setupLog(self, fd):
logger = getLogger()
handler = StreamHandler(fd)
logger.addHandler(handler)
if self.options.debug:
level = DEBUG
elif self.options.verbose:
level = INFO
elif self.options.quiet:
level = ERROR
else:
level = WARNING
logger.setLevel(level)
def processOptions(self):
if self.program:
self.program[0] = locateProgram(self.program[0])
def createLogOptions(self, parser):
log = OptionGroup(parser, "Logging")
log.add_option("--quiet", "-q", help="Be quiet (set log level to ERROR)",
action="store_true", default=False)
log.add_option("--verbose", "-v", help="Debug mode (set log level to INFO)",
action="store_true", default=False)
log.add_option("--debug", help="Debug mode (set log level to DEBUG)",
action="store_true", default=False)
parser.add_option_group(log)
def createChild(self, arguments, env=None):
return createChild(arguments, self.options.no_stdout, env)
def setupDebugger(self):
# Set ptrace options
if self.options.fork:
try:
self.debugger.traceFork()
except DebuggerError:
error("--fork option is not supported by your OS, sorry!")
exit(1)
if self.options.trace_exec:
self.debugger.traceExec()
def createProcess(self):
if self.options.pid:
pid = self.options.pid
is_attached = False
error("Attach process %s" % pid)
else:
pid = self.createChild(self.program)
is_attached = True
try:
return self.debugger.addProcess(pid, is_attached=is_attached)
except (ProcessExit, PtraceError) as err:
if isinstance(err, PtraceError) \
and err.errno == EPERM:
error(
"ERROR: You are not allowed to trace process %s (permission denied or process already traced)" % pid)
else:
error("ERROR: Process can no be attached! %s" % err)
return None
def createCommonOptions(self, parser):
parser.add_option("--pid", "-p", help="Attach running process specified by its identifier",
type="int", default=None)
parser.add_option("--fork", "-f", help="Trace fork and child process",
action="store_true", default=False)
parser.add_option("--trace-exec", help="Trace execve() event",
action="store_true", default=False)
parser.add_option("--no-stdout", help="Use /dev/null as stdout/stderr, or close stdout and stderr if /dev/null doesn't exist",
action="store_true", default=False)
python-ptrace-0.9.3/ptrace/debugger/backtrace.py 0000664 0001750 0001750 00000005551 13047323113 022142 0 ustar haypo haypo 0000000 0000000 from ptrace.ctypes_tools import formatAddress, formatWordHex
from ptrace.cpu_info import CPU_WORD_SIZE, CPU_MAX_UINT
from ptrace import PtraceError
from ptrace.six.moves import xrange
class BacktraceFrame(object):
"""
Backtrace frame.
Attributes:
- ip: instruction pointer
- name: name of the function
- arguments: value of the arguments
"""
def __init__(self, ip):
self.ip = ip
self.name = u"???"
self.arguments = []
def __str__(self):
arguments = (formatWordHex(arg) for arg in self.arguments)
return u"IP=%s: %s (%s)" % (formatAddress(self.ip), self.name, ", ".join(arguments))
class Backtrace(object):
"""
Backtrace: all process frames since the start function.
"""
def __init__(self):
self.frames = []
self.truncated = False
def append(self, frame):
self.frames.append(frame)
def __iter__(self):
return iter(self.frames)
def __len__(self):
return len(self.frames)
def getBacktrace(process, max_args=6, max_depth=20):
"""
Get the current backtrace of the specified process:
- max_args: maximum number of arguments in a frame
- max_depth: maximum number of frames
Return a Backtrace object.
"""
backtrace = Backtrace()
# Get current instruction and frame pointer
ip = process.getInstrPointer()
fp = process.getFramePointer()
depth = 0
while True:
# Hit maximum trace depth?
if max_depth <= depth:
backtrace.truncated = True
break
# Read next frame pointer
try:
nextfp = process.readWord(fp)
except PtraceError:
nextfp = None
# Guess number of function argument
if fp and nextfp:
nargs = ((nextfp - fp) // CPU_WORD_SIZE) - 2
nargs = min(nargs, max_args)
else:
nargs = 0
# Create frame
frame = getBacktraceFrame(process, ip, fp, nargs)
backtrace.append(frame)
# End of the stack?
if not nextfp:
break
# Move to next instruction/frame pointer
ip = process.readWord(fp + CPU_WORD_SIZE)
if ip == CPU_MAX_UINT:
# Linux hack to detect end of the stack
break
fp = nextfp
depth += 1
return backtrace
def getBacktraceFrame(process, ip, fp, nargs):
"""
Get a backtrace frame:
- ip: instruction pointer
- fp: frame pointer
- nargs: number of arguments
Return a BacktraceFrame object.
"""
frame = BacktraceFrame(ip)
address = fp + CPU_WORD_SIZE
try:
for index in xrange(nargs):
address += CPU_WORD_SIZE
word = process.readWord(address)
frame.arguments.append(word)
except PtraceError:
# Ignore argument read error
pass
return frame
python-ptrace-0.9.3/ptrace/debugger/parse_expr.py 0000664 0001750 0001750 00000004001 13047323112 022357 0 ustar haypo haypo 0000000 0000000 import re
# Match a register name: $eax, $gp0, $orig_eax
REGISTER_REGEX = re.compile(r"([a-z]+[a-z0-9_]+)")
# Hexadecimal number (e.g. 0xa)
HEXADECIMAL_REGEX = re.compile(r"0x[0-9a-f]+")
# Make sure that the expression does not contain invalid characters
# Examples:
# (1-2)<<5
# 340&91
EXPR_REGEX = re.compile(r"^[()<>+*/&0-9-]+$")
def replaceHexadecimal(regs):
"""
Convert an hexadecimal number to decimal number (as string).
Callback used by parseExpression().
"""
text = regs.group(0)
if text.startswith("0x"):
text = text[2:]
elif not re.search("[a-f]", text):
return text
value = int(text, 16)
return str(value)
def parseExpression(process, text):
"""
Parse an expression. Syntax:
- "10": decimal number
- "0x10": hexadecimal number
- "eax": register value
- "a+b", "a-b", "a*b", "a/b", "a**b", "a<>b": operators
>>> from ptrace.mockup import FakeProcess
>>> process = FakeProcess()
>>> parseExpression(process, "1+1")
2
>>> process.setreg("eax", 3)
>>> parseExpression(process, "eax*0x10")
48
"""
# Remove spaces and convert to lower case
text = text.strip()
orig_text = text
if " " in text:
raise ValueError("Space are forbidden: %r" % text)
text = text.lower()
def readRegister(regs):
name = regs.group(1)
value = process.getreg(name)
return str(value)
# Replace hexadecimal by decimal
text = HEXADECIMAL_REGEX.sub(replaceHexadecimal, text)
# Replace registers by their value
text = REGISTER_REGEX.sub(readRegister, text)
# Reject invalid characters
if not EXPR_REGEX.match(text):
raise ValueError("Invalid expression: %r" % orig_text)
# Use integer division (a//b) instead of float division (a/b)
text = text.replace("/", "//")
# Finally, evaluate the expression
try:
value = eval(text)
except SyntaxError:
raise ValueError("Invalid expression: %r" % orig_text)
return value
python-ptrace-0.9.3/ptrace/debugger/memory_mapping.py 0000664 0001750 0001750 00000010044 13047323111 023235 0 ustar haypo haypo 0000000 0000000 from ptrace.os_tools import HAS_PROC
from ptrace.debugger.process_error import ProcessError
from ptrace.ctypes_tools import formatAddress
import re
from weakref import ref
if HAS_PROC:
from ptrace.linux_proc import openProc, ProcError
PROC_MAP_REGEX = re.compile(
# Address range: '08048000-080b0000 '
r'([0-9a-f]+)-([0-9a-f]+) '
# Permission: 'r-xp '
r'(.{4}) '
# Offset: '0804d000'
r'([0-9a-f]+) '
# Device (major:minor): 'fe:01 '
r'([0-9a-f]{2}):([0-9a-f]{2}) '
# Inode: '3334030'
r'([0-9]+)'
# Filename: ' /usr/bin/synergyc'
r'(?: +(.*))?')
class MemoryMapping(object):
"""
Process memory mapping (metadata about the mapping).
Attributes:
- start (int): first byte address
- end (int): last byte address + 1
- permissions (str)
- offset (int): for file, offset in bytes from the file start
- major_device / minor_device (int): major / minor device number
- inode (int)
- pathname (str)
- _process: weak reference to the process
Operations:
- "address in mapping" checks the address is in the mapping.
- "search(somestring)" returns the offsets of "somestring" in the mapping
- "str(mapping)" create one string describing the mapping
- "repr(mapping)" create a string representation of the mapping,
useful in list contexts
"""
def __init__(self, process, start, end, permissions, offset, major_device, minor_device, inode, pathname):
self._process = ref(process)
self.start = start
self.end = end
self.permissions = permissions
self.offset = offset
self.major_device = major_device
self.minor_device = minor_device
self.inode = inode
self.pathname = pathname
def __contains__(self, address):
return self.start <= address < self.end
def __str__(self):
text = "%s-%s" % (formatAddress(self.start), formatAddress(self.end))
if self.pathname:
text += " => %s" % self.pathname
text += " (%s)" % self.permissions
return text
__repr__ = __str__
def search(self, bytestr):
process = self._process()
bytestr_len = len(bytestr)
buf_len = 64 * 1024
if buf_len < bytestr_len:
buf_len = bytestr_len
remaining = self.end - self.start
covered = self.start
while remaining >= bytestr_len:
if remaining > buf_len:
requested = buf_len
else:
requested = remaining
data = process.readBytes(covered, requested)
if data == "":
break
offset = data.find(bytestr)
if (offset == -1):
skip = requested - bytestr_len + 1
else:
yield (covered + offset)
skip = offset + bytestr_len
covered += skip
remaining -= skip
def readProcessMappings(process):
"""
Read all memory mappings of the specified process.
Return a list of MemoryMapping objects, or empty list if it's not possible
to read the mappings.
May raise a ProcessError.
"""
maps = []
if not HAS_PROC:
return maps
try:
mapsfile = openProc("%s/maps" % process.pid)
except ProcError as err:
raise ProcessError(process, "Unable to read process maps: %s" % err)
try:
for line in mapsfile:
line = line.rstrip()
match = PROC_MAP_REGEX.match(line)
if not match:
raise ProcessError(
process, "Unable to parse memory mapping: %r" % line)
map = MemoryMapping(
process,
int(match.group(1), 16),
int(match.group(2), 16),
match.group(3),
int(match.group(4), 16),
int(match.group(5), 16),
int(match.group(6), 16),
int(match.group(7)),
match.group(8))
maps.append(map)
finally:
mapsfile.close()
return maps
python-ptrace-0.9.3/ptrace/debugger/process_error.py 0000664 0001750 0001750 00000000317 13047323111 023103 0 ustar haypo haypo 0000000 0000000 from ptrace.error import PtraceError
class ProcessError(PtraceError):
def __init__(self, process, message):
PtraceError.__init__(self, message, pid=process.pid)
self.process = process
python-ptrace-0.9.3/ptrace/debugger/child.py 0000664 0001750 0001750 00000007565 13047323113 021315 0 ustar haypo haypo 0000000 0000000 """
Error pipe and serialization code comes from Python 2.5 subprocess module.
"""
from os import (
fork, execvp, execvpe, waitpid,
close, dup2, pipe,
read, write, devnull, sysconf)
from sys import exc_info
from traceback import format_exception
from ptrace.os_tools import RUNNING_WINDOWS
from ptrace.binding import ptrace_traceme
from ptrace import PtraceError
from sys import exit
from errno import EINTR
import fcntl
import pickle
try:
MAXFD = sysconf("SC_OPEN_MAX")
except:
MAXFD = 256
class ChildError(RuntimeError):
pass
class ChildPtraceError(ChildError):
pass
def _set_cloexec_flag(fd):
if RUNNING_WINDOWS:
return
try:
cloexec_flag = fcntl.FD_CLOEXEC
except AttributeError:
cloexec_flag = 1
old = fcntl.fcntl(fd, fcntl.F_GETFD)
fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
def _waitpid_no_intr(pid, options):
"""Like os.waitpid, but retries on EINTR"""
while True:
try:
return waitpid(pid, options)
except OSError as e:
if e.errno == EINTR:
continue
else:
raise
def _read_no_intr(fd, buffersize):
"""Like os.read, but retries on EINTR"""
while True:
try:
return read(fd, buffersize)
except OSError as e:
if e.errno == EINTR:
continue
else:
raise
def _write_no_intr(fd, s):
"""Like os.write, but retries on EINTR"""
while True:
try:
return write(fd, s)
except OSError as e:
if e.errno == EINTR:
continue
else:
raise
def _createParent(pid, errpipe_read):
# Wait for exec to fail or succeed; possibly raising exception
data = _read_no_intr(errpipe_read, 1048576) # Exceptions limited to 1 MB
close(errpipe_read)
if data:
_waitpid_no_intr(pid, 0)
child_exception = pickle.loads(data)
raise child_exception
def _createChild(arguments, no_stdout, env, errpipe_write):
# Child code
try:
ptrace_traceme()
except PtraceError as err:
raise ChildError(str(err))
# Close all files except 0, 1, 2 and errpipe_write
for fd in range(3, MAXFD):
if fd == errpipe_write:
continue
try:
close(fd)
except OSError:
pass
try:
_execChild(arguments, no_stdout, env)
except:
exc_type, exc_value, tb = exc_info()
# Save the traceback and attach it to the exception object
exc_lines = format_exception(exc_type, exc_value, tb)
exc_value.child_traceback = ''.join(exc_lines)
_write_no_intr(errpipe_write, pickle.dumps(exc_value))
exit(255)
def _execChild(arguments, no_stdout, env):
if no_stdout:
try:
null = open(devnull, 'wb')
dup2(null.fileno(), 1)
dup2(1, 2)
null.close()
except IOError as err:
close(2)
close(1)
try:
if env is not None:
execvpe(arguments[0], arguments, env)
else:
execvp(arguments[0], arguments)
except Exception as err:
raise ChildError(str(err))
def createChild(arguments, no_stdout, env=None):
"""
Create a child process:
- arguments: list of string where (e.g. ['ls', '-la'])
- no_stdout: if True, use null device for stdout/stderr
- env: environment variables dictionary
Use:
- env={} to start with an empty environment
- env=None (default) to copy the environment
"""
errpipe_read, errpipe_write = pipe()
_set_cloexec_flag(errpipe_write)
# Fork process
pid = fork()
if pid:
close(errpipe_write)
_createParent(pid, errpipe_read)
return pid
else:
close(errpipe_read)
_createChild(arguments, no_stdout, env, errpipe_write)
python-ptrace-0.9.3/ptrace/debugger/ptrace_signal.py 0000664 0001750 0001750 00000016446 13047323113 023043 0 ustar haypo haypo 0000000 0000000 from logging import error
from ptrace.disasm import HAS_DISASSEMBLER
from signal import SIGFPE, SIGSEGV, SIGABRT
try:
from signal import SIGCHLD
except ImportError:
SIGCHLD = None
try:
from signal import SIGBUS
except ImportError:
SIGBUS = None
from ptrace.os_tools import RUNNING_LINUX
from ptrace.cpu_info import CPU_64BITS
from ptrace.debugger import ProcessEvent
from ptrace.error import PtraceError
from ptrace import signalName
from ptrace.debugger.signal_reason import (
DivisionByZero, Abort, StackOverflow,
InvalidMemoryAccess, InvalidRead, InvalidWrite,
InstructionError, ChildExit)
from ptrace.debugger.parse_expr import parseExpression
import re
# Match a pointer dereference (e.g. "DWORD [EDX+0x8]")
DEREF_REGEX = r'(?P(BYTE|WORD|DWORD|DQWORD) )?\[(?P[^]]+)\]'
NAMED_WORD_SIZE = {
'BYTE': 1,
'WORD': 2,
'DWORD': 4,
'DQWORD': 8,
}
# Match any Intel instruction (e.g. "ADD")
INSTR_REGEX = '(?:[A-Z]{3,10})'
def findDerefSize(match):
name = match.group("deref_size")
try:
return NAMED_WORD_SIZE[name]
except KeyError:
return None
def evalFaultAddress(process, match):
expr = match.group('deref')
if not expr:
return None
try:
return parseExpression(process, expr)
except ValueError as err:
error("err: %s" % err)
return None
class ProcessSignal(ProcessEvent):
def __init__(self, signum, process):
# Initialize attributes
self.name = signalName(signum)
ProcessEvent.__init__(self, process, "Signal %s" % self.name)
self.signum = signum
self.reason = None
def _analyze(self):
if self.signum in (SIGSEGV, SIGBUS):
self.memoryFault()
elif self.signum == SIGFPE:
self.mathError()
elif self.signum == SIGCHLD:
self.childExit()
elif self.signum == SIGABRT:
self.reason = Abort()
return self.reason
def getInstruction(self):
if not HAS_DISASSEMBLER:
return None
try:
return self.process.disassembleOne()
except PtraceError:
return None
def memoryFaultInstr(self, instr, fault_address):
asm = instr.text
# Invalid write (e.g. "MOV [...], value")
match = re.search(r"^(?:MOV|TEST)[A-Z]* %s," % DEREF_REGEX, asm)
if match:
if fault_address is None:
fault_address = evalFaultAddress(self.process, match)
self.reason = InvalidWrite(fault_address, size=findDerefSize(match),
instr=instr, process=self.process)
return
# Invalid read (e.g. "CMP BYTE [EAX+EDX-0x1], 0x0")
match = re.search(r"^%s %s," % (INSTR_REGEX, DEREF_REGEX), asm)
if match:
if fault_address is None:
fault_address = evalFaultAddress(self.process, match)
self.reason = InvalidRead(fault_address, size=findDerefSize(match),
instr=instr, process=self.process)
return
# Invalid read (e.g. "MOV reg, [...]")
match = re.match(r"%s [^,]+, %s" % (INSTR_REGEX, DEREF_REGEX), asm)
if match:
if fault_address is None:
fault_address = evalFaultAddress(self.process, match)
self.reason = InvalidRead(fault_address, size=findDerefSize(match),
instr=instr, process=self.process)
return
# MOVS* and SCAS* instructions (e.g. "MOVSB" or "REP SCASD")
match = re.search(
r"^(?:REP(?:NZ)? )?(?PMOVS|SCAS)(?P[BWD])?", asm)
if match:
self.reason = self.movsInstr(fault_address, instr, match)
return
def movsInstr(self, fault_address, instr, match):
operator = match.group("operator")
suffix = match.group("suffix")
size = {'B': 1, 'W': 2, 'D': 4}.get(suffix)
error_cls = InvalidMemoryAccess
try:
process = self.process
if CPU_64BITS:
source_reg = 'rsi'
dest_reg = 'rdi'
else:
source_reg = 'esi'
dest_reg = 'edi'
source_addr = process.getreg(source_reg)
registers = {source_reg: source_addr}
write = (operator == 'MOVS')
if write:
dest_addr = process.getreg(dest_reg)
registers[dest_reg] = dest_addr
if fault_address is not None:
if fault_address == source_addr:
error_cls = InvalidRead
if write and fault_address == dest_addr:
error_cls = InvalidWrite
else:
if write:
fault_address = (source_addr, dest_addr)
else:
fault_address = (source_addr,)
except PtraceError:
registers = {}
return error_cls(fault_address, size=size, instr=instr,
registers=registers, process=self.process)
def getSignalInfo(self):
if RUNNING_LINUX:
return self.process.getsiginfo()
else:
return None
def memoryFault(self):
# Get fault
siginfo = self.getSignalInfo()
if siginfo:
fault_address = siginfo._sigfault._addr
if not fault_address:
fault_address = 0
else:
fault_address = None
# Get current instruction
instr = self.getInstruction()
# Call to invalid address?
if fault_address is not None:
try:
ip = self.process.getInstrPointer()
if ip == fault_address:
self.reason = InstructionError(ip, process=self.process)
return
except PtraceError:
pass
# Stack overflow?
stack = self.process.findStack()
if stack:
sp = self.process.getStackPointer()
if not (stack.start <= sp <= stack.end):
self.reason = StackOverflow(
sp, stack, instr=instr, process=self.process)
return
# Guess error type using the assembler instruction
if instr:
self.memoryFaultInstr(instr, fault_address)
if self.reason:
return
# Last chance: use generic invalid memory access error
self.reason = InvalidMemoryAccess(
fault_address, instr=instr, process=self.process)
def mathError(self):
instr = self.getInstruction()
if not instr:
return
match = re.match(r"I?DIV (.*)", instr.text)
if not match:
return
self.reason = DivisionByZero(instr=instr, process=self.process)
def childExit(self):
siginfo = self.getSignalInfo()
if siginfo:
child = siginfo._sigchld
self.reason = ChildExit(child.pid, child.status, child.uid)
else:
self.reason = ChildExit()
def display(self, log=None):
self._analyze()
if not log:
log = error
log("-" * 60)
log("PID: %s" % self.process.pid)
log("Signal: %s" % self.name)
if self.reason:
self.reason.display(log)
log("-" * 60)
python-ptrace-0.9.3/ptrace/signames.py 0000664 0001750 0001750 00000002777 13047323324 020260 0 ustar haypo haypo 0000000 0000000 """
Name of process signals.
SIGNAMES contains a dictionary mapping a signal number to it's name. But you
should better use signalName() instead of SIGNAMES since it returns a string
even if the signal is unknown.
"""
PREFERRED_NAMES = ("SIGABRT", "SIGHUP", "SIGCHLD", "SIGPOLL")
def getSignalNames():
"""
Create signal names dictionary (e.g. 9 => 'SIGKILL') using dir(signal).
If multiple signal names have the same number, use the first matching name
in PREFERRED_NAME to select preferred name (e.g. SIGIOT=SIGABRT=17).
"""
import signal
allnames = {}
for name in dir(signal):
if not name.startswith("SIG"):
continue
signum = getattr(signal, name)
try:
allnames[signum].append(name)
except KeyError:
allnames[signum] = [name]
signames = {}
for signum, names in allnames.items():
if not signum:
# Skip signal 0
continue
name = None
for preferred in PREFERRED_NAMES:
if preferred in names:
name = preferred
break
if not name:
name = names[0]
signames[signum] = name
return signames
SIGNAMES = getSignalNames()
def signalName(signum):
"""
Get the name of a signal
>>> from signal import SIGINT
>>> signalName(SIGINT)
'SIGINT'
>>> signalName(404)
'signal<404>'
"""
try:
return SIGNAMES[signum]
except KeyError:
return "signal<%s>" % signum
python-ptrace-0.9.3/ptrace/pydistorm.py 0000664 0001750 0001750 00000006710 13047323324 020473 0 ustar haypo haypo 0000000 0000000 """
:[diStorm64 1.7.27}:
Copyright RageStorm (C) 2007, Gil Dabah
diStorm is licensed under the BSD license.
http://ragestorm.net/distorm/
---
Python binding of diStorm64 library written by Victor Stinner
"""
from ctypes import cdll, c_long, c_ulong, c_int, c_uint, c_char, POINTER, Structure, addressof, byref, c_void_p, create_string_buffer, sizeof, cast
from ptrace.six import binary_type
# Define (u)int32_t and (u)int64_t types
int32_t = c_int
uint32_t = c_uint
if sizeof(c_ulong) == 8:
int64_t = c_long
uint64_t = c_ulong
else:
from ctypes import c_longlong, c_ulonglong
assert sizeof(c_longlong) == 8
assert sizeof(c_ulonglong) == 8
int64_t = c_longlong
uint64_t = c_ulonglong
SUPPORT_64BIT_OFFSET = True
if SUPPORT_64BIT_OFFSET:
_OffsetType = uint64_t
else:
_OffsetType = uint32_t
LIB_FILENAME = 'libdistorm64.so'
distorm = cdll.LoadLibrary(LIB_FILENAME)
Decode16Bits = 0
Decode32Bits = 1
Decode64Bits = 2
DECODERS = (Decode16Bits, Decode32Bits, Decode64Bits)
internal_decode = distorm.internal_decode
DECRES_NONE = 0
DECRES_SUCCESS = 1
DECRES_MEMORYERR = 2
DECRES_INPUTERR = 3
MAX_INSTRUCTIONS = 100
MAX_TEXT_SIZE = 60
class _WString(Structure):
_fields_ = (
("pos", c_uint),
("p", c_char * MAX_TEXT_SIZE),
)
def __str__(self):
# FIXME: Use pos?
return self.p
class _DecodedInst(Structure):
_fields_ = (
("mnemonic", _WString),
("operands", _WString),
("instructionHex", _WString),
("size", c_uint),
("offset", _OffsetType),
)
def __str__(self):
return "%s %s" % (self.mnemonic, self.operands)
internal_decode.argtypes = (_OffsetType, c_void_p,
c_int, c_int, c_void_p, c_uint, POINTER(c_uint))
def Decode(codeOffset, code, dt=Decode32Bits):
"""
Errors: TypeError, IndexError, MemoryError, ValueError
"""
# Check arguments
if not isinstance(codeOffset, (int, long)):
raise TypeError("codeOffset have to be an integer")
if not isinstance(code, binary_type):
raise TypeError("code have to be a %s, not %s"
% (binary_type.__name__, type(code).__name__))
if dt not in DECODERS:
raise IndexError(
"Decoding-type must be either Decode16Bits, Decode32Bits or Decode64Bits.")
# Allocate memory for decoder
code_buffer = create_string_buffer(code)
decodedInstructionsCount = c_uint()
result = create_string_buffer(sizeof(_DecodedInst) * MAX_INSTRUCTIONS)
# Prepare arguments
codeLen = len(code)
code = addressof(code_buffer)
while codeLen:
# Call internal decoder
res = internal_decode(codeOffset, code, codeLen, dt, result,
MAX_INSTRUCTIONS, byref(decodedInstructionsCount))
# Check for errors
if res == DECRES_INPUTERR:
raise ValueError("Invalid argument")
count = decodedInstructionsCount.value
if res == DECRES_MEMORYERR and not count:
raise MemoryError()
# No more instruction
if not count:
break
# Yield instruction and compute decoded size
size = 0
instr_array = cast(result, POINTER(_DecodedInst))
for index in range(count):
instr = instr_array[index]
size += instr.size
yield instr
# Update parameters to move to next instructions
code += size
codeOffset += size
codeLen -= size
python-ptrace-0.9.3/ptrace/mockup.py 0000664 0001750 0001750 00000000370 13047323111 017725 0 ustar haypo haypo 0000000 0000000 """
Mockup classes used in unit tests.
"""
class FakeProcess(object):
def __init__(self):
self.regs = {}
def setreg(self, name, value):
self.regs[name] = value
def getreg(self, name):
return self.regs[name]
python-ptrace-0.9.3/ptrace/func_call.py 0000664 0001750 0001750 00000004514 13047323112 020362 0 ustar haypo haypo 0000000 0000000 from ptrace.func_arg import FunctionArgument
class FunctionCallOptions(object):
"""
Options to format a function call and its arguments.
"""
def __init__(self,
write_types=False, write_argname=False,
replace_socketcall=True, string_max_length=300,
write_address=False, max_array_count=20):
self.write_address = write_address
self.write_types = write_types
self.write_argname = write_argname
self.replace_socketcall = replace_socketcall
self.string_max_length = string_max_length
self.max_array_count = max_array_count
self.instr_pointer = False
class FunctionCall(object):
"""
A function call. Attributes:
- name (str): function name
- arguments: list of FunctionArgument objects
- restype (str, optional): result type
- resvalue (optional): result value
- argument_class: class used to build the new arguments
Methods:
- format(): create a string representation of the call
- addArgument(): add a new argument
- clearArguments(): remove all arguments
"""
def __init__(self, name, options, argument_class=FunctionArgument):
self.name = name
self.options = options
self.arguments = []
self.restype = None
self.resvalue = None
self.argument_class = argument_class
def addArgument(self, value=None, name=None, type=None):
arg = self.argument_class(
self, len(self.arguments), self.options, value, type, name)
self.arguments.append(arg)
def clearArguments(self):
self.arguments = []
def __getitem__(self, key):
if isinstance(key, str):
for arg in self.arguments:
if arg.name == key:
return arg
raise KeyError("%r has no argument called %r" % (self, key))
else:
# Integer key
return self.arguments[key]
def format(self):
arguments = [arg.format() for arg in self.arguments]
arguments = ", ".join(arguments)
if self.restype and self.options.write_types:
return "%s %s(%s)" % (self.restype, self.name, arguments)
else:
return "%s(%s)" % (self.name, arguments)
def __repr__(self):
return "" % self.name
python-ptrace-0.9.3/ptrace/cpu_info.py 0000664 0001750 0001750 00000002770 13047323113 020241 0 ustar haypo haypo 0000000 0000000 """
Constants about the CPU:
- CPU_BIGENDIAN (bool)
- CPU_64BITS (bool)
- CPU_WORD_SIZE (int)
- CPU_MAX_UINT (int)
- CPU_PPC32 (bool)
- CPU_PPC64 (bool)
- CPU_I386 (bool)
- CPU_X86_64 (bool)
- CPU_INTEL (bool)
- CPU_POWERPC (bool)
"""
try:
from os import uname
HAS_UNAME = True
except ImportError:
HAS_UNAME = False
from platform import architecture
from sys import byteorder
from ctypes import sizeof, c_void_p
CPU_BIGENDIAN = (byteorder == 'big')
CPU_64BITS = (sizeof(c_void_p) == 8)
if CPU_64BITS:
CPU_WORD_SIZE = 8 # bytes
CPU_MAX_UINT = 0xffffffffffffffff
else:
CPU_WORD_SIZE = 4 # bytes
CPU_MAX_UINT = 0xffffffff
if HAS_UNAME:
# guess machine type using uname()
_machine = uname()[4]
CPU_PPC32 = (_machine == 'ppc')
CPU_PPC64 = (_machine == 'ppc64')
CPU_I386 = (_machine in ("i386", "i686")) # compatible Intel 32 bits
CPU_X86_64 = (_machine in ("x86_64", "amd64")) # compatible Intel 64 bits
CPU_ARM = _machine.startswith('arm')
del _machine
else:
# uname() fallback for Windows
# I hope that your Windows doesn't run on PPC32/PPC64
CPU_PPC32 = False
CPU_PPC64 = False
CPU_I386 = False
CPU_X86_64 = False
CPU_ARM = False
bits, linkage = architecture()
if bits == '32bit':
CPU_I386 = True
elif bits == '64bit':
CPU_X86_64 = True
else:
raise ValueError("Unknown architecture bits: %r" % bits)
CPU_INTEL = (CPU_I386 or CPU_X86_64)
CPU_POWERPC = (CPU_PPC32 or CPU_PPC64)
python-ptrace-0.9.3/ptrace/process_tools.py 0000664 0001750 0001750 00000007437 13047323112 021341 0 ustar haypo haypo 0000000 0000000 from ptrace.os_tools import RUNNING_LINUX, RUNNING_WINDOWS
if RUNNING_LINUX:
from ptrace.linux_proc import (ProcError, openProc,
readProcessProcList, readProcessLink, readProcessStat)
from ptrace.signames import signalName # noqa
if not RUNNING_WINDOWS:
from os import (
WIFSTOPPED, WSTOPSIG,
WIFSIGNALED, WTERMSIG,
WIFEXITED, WEXITSTATUS,
WCOREDUMP)
def dumpProcessInfo(log, pid, max_length=None):
"""
Dump all information about a process:
- log: callback to write display one line
- pid: process identifier
- max_length (default: None): maximum number of environment variables
"""
if not RUNNING_LINUX:
log("Process ID: %s" % pid)
return
try:
stat = readProcessStat(pid)
except ProcError:
# Permission denied
stat = None
text = "Process ID: %s" % pid
if stat:
text += " (parent: %s)" % stat.ppid
log(text)
if stat:
state = stat.state
try:
state = "%s (%s)" % (state, stat.STATE_NAMES[state])
except KeyError:
pass
log("Process state: %s" % state)
try:
log("Process command line: %r" % readProcessProcList(pid, 'cmdline'))
except ProcError:
# Permission denied
pass
try:
env = readProcessProcList(pid, 'environ')
if max_length:
# Truncate environment if it's too long
length = 0
removed = 0
index = 0
while index < len(env):
var = env[index]
if max_length < length + len(var):
del env[index]
removed += 1
else:
length += len(var)
index += 1
env = ', '.join("%s=%r" % tuple(item.split("=", 1))
for item in env)
if removed:
env += ', ... (skip %s vars)' % removed
log("Process environment: %s" % env)
except ProcError:
# Permission denied
pass
try:
log("Process working directory: %s" % readProcessLink(pid, 'cwd'))
except ProcError:
# Permission denied
pass
try:
user = None
group = None
status_file = openProc("%s/status" % pid)
for line in status_file:
if line.startswith("Uid:"):
user = [int(id) for id in line[5:].split("\t")]
if line.startswith("Gid:"):
group = [int(id) for id in line[5:].split("\t")]
status_file.close()
if user:
text = "User identifier: %s" % user[0]
if user[0] != user[1]:
text += " (effective: %s)" % user[1]
log(text)
if group:
text = "Group identifier: %s" % group[0]
if group[0] != group[1]:
text += " (effective: %s)" % group[1]
log(text)
except ProcError:
# Permission denied
pass
def formatProcessStatus(status, title="Process"):
"""
Format a process status (integer) as a string.
"""
if RUNNING_WINDOWS:
raise NotImplementedError()
if WIFSTOPPED(status):
signum = WSTOPSIG(status)
text = "%s stopped by signal %s" % (title, signalName(signum))
elif WIFSIGNALED(status):
signum = WTERMSIG(status)
text = "%s killed by signal %s" % (title, signalName(signum))
else:
if not WIFEXITED(status):
raise ValueError("Invalid status: %r" % status)
exitcode = WEXITSTATUS(status)
if exitcode:
text = "%s exited with code %s" % (title, exitcode)
else:
text = "%s exited normally" % title
if WCOREDUMP(status):
text += " (core dumped)"
return text
python-ptrace-0.9.3/ptrace/logging_tools.py 0000664 0001750 0001750 00000001321 13047323111 021272 0 ustar haypo haypo 0000000 0000000 from ptrace.tools import minmax
from logging import ERROR, WARNING, INFO, DEBUG
def getLogFunc(logger, level):
"""
Get the logger function for the specified logging level.
"""
if level == ERROR:
return logger.error
elif level == WARNING:
return logger.warning
elif level == INFO:
return logger.info
elif level == DEBUG:
return logger.debug
else:
return logger.error
def changeLogLevel(level, delta):
"""
Compute log level and make sure that the result is in DEBUG..ERROR.
>>> changeLogLevel(ERROR, -1) == WARNING
True
>>> changeLogLevel(DEBUG, 1) == INFO
True
"""
return minmax(DEBUG, level + delta * 10, ERROR)
python-ptrace-0.9.3/ptrace/disasm.py 0000664 0001750 0001750 00000004756 13047323111 017723 0 ustar haypo haypo 0000000 0000000 """
Disassembler: only enabled if HAS_DISASSEMBLER is True.
"""
try:
from ptrace.cpu_info import CPU_I386, CPU_X86_64
try:
from distorm3 import Decode
if CPU_X86_64:
from distorm3 import Decode64Bits as DecodeBits
MAX_INSTR_SIZE = 11
elif CPU_I386:
from distorm3 import Decode32Bits as DecodeBits
MAX_INSTR_SIZE = 8
else:
raise ImportError("CPU not supported")
DISTORM3 = True
except ImportError as err:
DISTORM3 = False
from ptrace.pydistorm import Decode
if CPU_X86_64:
from ptrace.pydistorm import Decode64Bits as DecodeBits
MAX_INSTR_SIZE = 11
elif CPU_I386:
from ptrace.pydistorm import Decode32Bits as DecodeBits
MAX_INSTR_SIZE = 8
else:
raise ImportError("CPU not supported")
from ptrace import PtraceError
class Instruction(object):
"""
A CPU instruction.
Attributes:
- address (int): address of the instruction
- size (int): size of the instruction in bytes
- mnemonic (str): name of the instruction
- operands (str): string describing the operands
- hexa (str): bytes of the instruction as an hexadecimal string
- text (str): string representing the whole instruction
"""
def __init__(self, instr):
if DISTORM3:
self.address, self.size, self.text, self.hexa = instr
else:
self.address = instr.offset
self.size = instr.size
self.hexa = str(instr.instructionHex)
self.text = "%s %s" % (instr.mnemonic, instr.operands)
def __str__(self):
return self.text
def disassemble(code, address=0x100):
"""
Disassemble the specified byte string, where address is the
address of the first instruction.
"""
for instr in Decode(address, code, DecodeBits):
yield Instruction(instr)
def disassembleOne(code, address=0x100):
"""
Disassemble the first instruction of the byte string, where
address is the address of the instruction.
"""
for instr in disassemble(code, address):
return instr
raise PtraceError("Unable to disassemble %r" % code)
HAS_DISASSEMBLER = True
except (ImportError, OSError) as err:
# OSError if libdistorm64.so doesn't exist
HAS_DISASSEMBLER = False
python-ptrace-0.9.3/ptrace/six.py 0000664 0001750 0001750 00000050501 13047323111 017233 0 ustar haypo haypo 0000000 0000000 """Utilities for writing code that runs on Python 2 and 3"""
# Copyright (c) 2010-2013 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import operator
import sys
import types
__author__ = "Benjamin Peterson "
__version__ = "1.4.1"
# Useful for very coarse version differentiation.
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
if PY3:
string_types = str,
integer_types = int,
class_types = type,
text_type = str
binary_type = bytes
MAXSIZE = sys.maxsize
else:
string_types = basestring,
integer_types = (int, long)
class_types = (type, types.ClassType)
text_type = unicode
binary_type = str
if sys.platform.startswith("java"):
# Jython always uses 32 bits.
MAXSIZE = int((1 << 31) - 1)
else:
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
class X(object):
def __len__(self):
return 1 << 31
try:
len(X())
except OverflowError:
# 32-bit
MAXSIZE = int((1 << 31) - 1)
else:
# 64-bit
MAXSIZE = int((1 << 63) - 1)
del X
def _add_doc(func, doc):
"""Add documentation to a function."""
func.__doc__ = doc
def _import_module(name):
"""Import module, returning the module after the last dot."""
__import__(name)
return sys.modules[name]
class _LazyDescr(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, tp):
result = self._resolve()
setattr(obj, self.name, result)
# This is a bit ugly, but it avoids running this again.
delattr(tp, self.name)
return result
class MovedModule(_LazyDescr):
def __init__(self, name, old, new=None):
super(MovedModule, self).__init__(name)
if PY3:
if new is None:
new = name
self.mod = new
else:
self.mod = old
def _resolve(self):
return _import_module(self.mod)
class MovedAttribute(_LazyDescr):
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
super(MovedAttribute, self).__init__(name)
if PY3:
if new_mod is None:
new_mod = name
self.mod = new_mod
if new_attr is None:
if old_attr is None:
new_attr = name
else:
new_attr = old_attr
self.attr = new_attr
else:
self.mod = old_mod
if old_attr is None:
old_attr = name
self.attr = old_attr
def _resolve(self):
module = _import_module(self.mod)
return getattr(module, self.attr)
class _MovedItems(types.ModuleType):
"""Lazy loading of moved objects"""
_moved_attributes = [
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
MovedAttribute("filterfalse", "itertools", "itertools",
"ifilterfalse", "filterfalse"),
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("reload_module", "__builtin__", "imp", "reload"),
MovedAttribute("reduce", "__builtin__", "functools"),
MovedAttribute("StringIO", "StringIO", "io"),
MovedAttribute("UserString", "UserString", "collections"),
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
MovedAttribute("zip_longest", "itertools", "itertools",
"izip_longest", "zip_longest"),
MovedModule("builtins", "__builtin__"),
MovedModule("configparser", "ConfigParser"),
MovedModule("copyreg", "copy_reg"),
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
MovedModule("http_cookies", "Cookie", "http.cookies"),
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
MovedModule("html_parser", "HTMLParser", "html.parser"),
MovedModule("http_client", "httplib", "http.client"),
MovedModule("email_mime_multipart", "email.MIMEMultipart",
"email.mime.multipart"),
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
MovedModule("cPickle", "cPickle", "pickle"),
MovedModule("queue", "Queue"),
MovedModule("reprlib", "repr"),
MovedModule("socketserver", "SocketServer"),
MovedModule("tkinter", "Tkinter"),
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
MovedModule("tkinter_scrolledtext", "ScrolledText",
"tkinter.scrolledtext"),
MovedModule("tkinter_simpledialog", "SimpleDialog",
"tkinter.simpledialog"),
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
MovedModule("tkinter_colorchooser", "tkColorChooser",
"tkinter.colorchooser"),
MovedModule("tkinter_commondialog", "tkCommonDialog",
"tkinter.commondialog"),
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
"tkinter.simpledialog"),
MovedModule("urllib_parse", __name__ +
".moves.urllib_parse", "urllib.parse"),
MovedModule("urllib_error", __name__ +
".moves.urllib_error", "urllib.error"),
MovedModule("urllib", __name__ + ".moves.urllib",
__name__ + ".moves.urllib"),
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
MovedModule("winreg", "_winreg"),
]
for attr in _moved_attributes:
setattr(_MovedItems, attr.name, attr)
del attr
moves = sys.modules[__name__ + ".moves"] = _MovedItems(__name__ + ".moves")
class Module_six_moves_urllib_parse(types.ModuleType):
"""Lazy loading of moved objects in six.moves.urllib_parse"""
_urllib_parse_moved_attributes = [
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
MovedAttribute("urljoin", "urlparse", "urllib.parse"),
MovedAttribute("urlparse", "urlparse", "urllib.parse"),
MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
MovedAttribute("quote", "urllib", "urllib.parse"),
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
MovedAttribute("unquote", "urllib", "urllib.parse"),
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
MovedAttribute("urlencode", "urllib", "urllib.parse"),
]
for attr in _urllib_parse_moved_attributes:
setattr(Module_six_moves_urllib_parse, attr.name, attr)
del attr
sys.modules[__name__ + ".moves.urllib_parse"] = Module_six_moves_urllib_parse(
__name__ + ".moves.urllib_parse")
sys.modules[__name__ + ".moves.urllib.parse"] = Module_six_moves_urllib_parse(
__name__ + ".moves.urllib.parse")
class Module_six_moves_urllib_error(types.ModuleType):
"""Lazy loading of moved objects in six.moves.urllib_error"""
_urllib_error_moved_attributes = [
MovedAttribute("URLError", "urllib2", "urllib.error"),
MovedAttribute("HTTPError", "urllib2", "urllib.error"),
MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
]
for attr in _urllib_error_moved_attributes:
setattr(Module_six_moves_urllib_error, attr.name, attr)
del attr
sys.modules[__name__ + ".moves.urllib_error"] = Module_six_moves_urllib_error(
__name__ + ".moves.urllib_error")
sys.modules[__name__ + ".moves.urllib.error"] = Module_six_moves_urllib_error(
__name__ + ".moves.urllib.error")
class Module_six_moves_urllib_request(types.ModuleType):
"""Lazy loading of moved objects in six.moves.urllib_request"""
_urllib_request_moved_attributes = [
MovedAttribute("urlopen", "urllib2", "urllib.request"),
MovedAttribute("install_opener", "urllib2", "urllib.request"),
MovedAttribute("build_opener", "urllib2", "urllib.request"),
MovedAttribute("pathname2url", "urllib", "urllib.request"),
MovedAttribute("url2pathname", "urllib", "urllib.request"),
MovedAttribute("getproxies", "urllib", "urllib.request"),
MovedAttribute("Request", "urllib2", "urllib.request"),
MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
MovedAttribute("HTTPPasswordMgrWithDefaultRealm",
"urllib2", "urllib.request"),
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
MovedAttribute("FileHandler", "urllib2", "urllib.request"),
MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
MovedAttribute("urlretrieve", "urllib", "urllib.request"),
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
MovedAttribute("URLopener", "urllib", "urllib.request"),
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
]
for attr in _urllib_request_moved_attributes:
setattr(Module_six_moves_urllib_request, attr.name, attr)
del attr
sys.modules[__name__ + ".moves.urllib_request"] = Module_six_moves_urllib_request(
__name__ + ".moves.urllib_request")
sys.modules[__name__ + ".moves.urllib.request"] = Module_six_moves_urllib_request(
__name__ + ".moves.urllib.request")
class Module_six_moves_urllib_response(types.ModuleType):
"""Lazy loading of moved objects in six.moves.urllib_response"""
_urllib_response_moved_attributes = [
MovedAttribute("addbase", "urllib", "urllib.response"),
MovedAttribute("addclosehook", "urllib", "urllib.response"),
MovedAttribute("addinfo", "urllib", "urllib.response"),
MovedAttribute("addinfourl", "urllib", "urllib.response"),
]
for attr in _urllib_response_moved_attributes:
setattr(Module_six_moves_urllib_response, attr.name, attr)
del attr
sys.modules[__name__ + ".moves.urllib_response"] = Module_six_moves_urllib_response(
__name__ + ".moves.urllib_response")
sys.modules[__name__ + ".moves.urllib.response"] = Module_six_moves_urllib_response(
__name__ + ".moves.urllib.response")
class Module_six_moves_urllib_robotparser(types.ModuleType):
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
_urllib_robotparser_moved_attributes = [
MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
]
for attr in _urllib_robotparser_moved_attributes:
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
del attr
sys.modules[__name__ + ".moves.urllib_robotparser"] = Module_six_moves_urllib_robotparser(
__name__ + ".moves.urllib_robotparser")
sys.modules[__name__ + ".moves.urllib.robotparser"] = Module_six_moves_urllib_robotparser(
__name__ + ".moves.urllib.robotparser")
class Module_six_moves_urllib(types.ModuleType):
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
parse = sys.modules[__name__ + ".moves.urllib_parse"]
error = sys.modules[__name__ + ".moves.urllib_error"]
request = sys.modules[__name__ + ".moves.urllib_request"]
response = sys.modules[__name__ + ".moves.urllib_response"]
robotparser = sys.modules[__name__ + ".moves.urllib_robotparser"]
sys.modules[
__name__ + ".moves.urllib"] = Module_six_moves_urllib(__name__ + ".moves.urllib")
def add_move(move):
"""Add an item to six.moves."""
setattr(_MovedItems, move.name, move)
def remove_move(name):
"""Remove item from six.moves."""
try:
delattr(_MovedItems, name)
except AttributeError:
try:
del moves.__dict__[name]
except KeyError:
raise AttributeError("no such move, %r" % (name,))
if PY3:
_meth_func = "__func__"
_meth_self = "__self__"
_func_closure = "__closure__"
_func_code = "__code__"
_func_defaults = "__defaults__"
_func_globals = "__globals__"
_iterkeys = "keys"
_itervalues = "values"
_iteritems = "items"
_iterlists = "lists"
else:
_meth_func = "im_func"
_meth_self = "im_self"
_func_closure = "func_closure"
_func_code = "func_code"
_func_defaults = "func_defaults"
_func_globals = "func_globals"
_iterkeys = "iterkeys"
_itervalues = "itervalues"
_iteritems = "iteritems"
_iterlists = "iterlists"
try:
advance_iterator = next
except NameError:
def advance_iterator(it):
return it.next()
next = advance_iterator
try:
callable = callable
except NameError:
def callable(obj):
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
if PY3:
def get_unbound_function(unbound):
return unbound
create_bound_method = types.MethodType
Iterator = object
else:
def get_unbound_function(unbound):
return unbound.im_func
def create_bound_method(func, obj):
return types.MethodType(func, obj, obj.__class__)
class Iterator(object):
def next(self):
return type(self).__next__(self)
callable = callable
_add_doc(get_unbound_function,
"""Get the function out of a possibly unbound function""")
get_method_function = operator.attrgetter(_meth_func)
get_method_self = operator.attrgetter(_meth_self)
get_function_closure = operator.attrgetter(_func_closure)
get_function_code = operator.attrgetter(_func_code)
get_function_defaults = operator.attrgetter(_func_defaults)
get_function_globals = operator.attrgetter(_func_globals)
def iterkeys(d, **kw):
"""Return an iterator over the keys of a dictionary."""
return iter(getattr(d, _iterkeys)(**kw))
def itervalues(d, **kw):
"""Return an iterator over the values of a dictionary."""
return iter(getattr(d, _itervalues)(**kw))
def iteritems(d, **kw):
"""Return an iterator over the (key, value) pairs of a dictionary."""
return iter(getattr(d, _iteritems)(**kw))
def iterlists(d, **kw):
"""Return an iterator over the (key, [values]) pairs of a dictionary."""
return iter(getattr(d, _iterlists)(**kw))
if PY3:
def b(s):
return s.encode("latin-1")
def u(s):
return s
unichr = chr
if sys.version_info[1] <= 1:
def int2byte(i):
return bytes((i,))
else:
# This is about 2x faster than the implementation above on 3.2+
int2byte = operator.methodcaller("to_bytes", 1, "big")
byte2int = operator.itemgetter(0)
indexbytes = operator.getitem
iterbytes = iter
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
else:
def b(s):
return s
def u(s):
return unicode(s, "unicode_escape")
unichr = unichr
int2byte = chr
def byte2int(bs):
return ord(bs[0])
def indexbytes(buf, i):
return ord(buf[i])
def iterbytes(buf):
return (ord(byte) for byte in buf)
import StringIO
StringIO = BytesIO = StringIO.StringIO
_add_doc(b, """Byte literal""")
_add_doc(u, """Text literal""")
if PY3:
import builtins
exec_ = getattr(builtins, "exec")
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
print_ = getattr(builtins, "print")
del builtins
else:
def exec_(_code_, _globs_=None, _locs_=None):
"""Execute code in a namespace."""
if _globs_ is None:
frame = sys._getframe(1)
_globs_ = frame.f_globals
if _locs_ is None:
_locs_ = frame.f_locals
del frame
elif _locs_ is None:
_locs_ = _globs_
exec("""exec _code_ in _globs_, _locs_""")
exec_("""def reraise(tp, value, tb=None):
raise tp, value, tb
""")
def print_(*args, **kwargs):
"""The new-style print function."""
fp = kwargs.pop("file", sys.stdout)
if fp is None:
return
def write(data):
if not isinstance(data, basestring):
data = str(data)
fp.write(data)
want_unicode = False
sep = kwargs.pop("sep", None)
if sep is not None:
if isinstance(sep, unicode):
want_unicode = True
elif not isinstance(sep, str):
raise TypeError("sep must be None or a string")
end = kwargs.pop("end", None)
if end is not None:
if isinstance(end, unicode):
want_unicode = True
elif not isinstance(end, str):
raise TypeError("end must be None or a string")
if kwargs:
raise TypeError("invalid keyword arguments to print()")
if not want_unicode:
for arg in args:
if isinstance(arg, unicode):
want_unicode = True
break
if want_unicode:
newline = unicode("\n")
space = unicode(" ")
else:
newline = "\n"
space = " "
if sep is None:
sep = space
if end is None:
end = newline
for i, arg in enumerate(args):
if i:
write(sep)
write(arg)
write(end)
_add_doc(reraise, """Reraise an exception.""")
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
return meta("NewBase", bases, {})
def add_metaclass(metaclass):
"""Class decorator for creating a class with a metaclass."""
def wrapper(cls):
orig_vars = cls.__dict__.copy()
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
for slots_var in orig_vars.get('__slots__', ()):
orig_vars.pop(slots_var)
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper
python-ptrace-0.9.3/ptrace/binding/ 0000775 0001750 0001750 00000000000 13160156527 017502 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/ptrace/binding/__init__.py 0000664 0001750 0001750 00000002213 13047323111 021576 0 ustar haypo haypo 0000000 0000000 from ptrace.binding.func import ( # noqa
HAS_PTRACE_SINGLESTEP, HAS_PTRACE_EVENTS,
HAS_PTRACE_IO, HAS_PTRACE_SIGINFO, HAS_PTRACE_GETREGS,
REGISTER_NAMES,
ptrace_attach, ptrace_traceme,
ptrace_detach, ptrace_kill,
ptrace_cont, ptrace_syscall,
ptrace_setregs,
ptrace_peektext, ptrace_poketext,
ptrace_peekuser,
ptrace_registers_t)
if HAS_PTRACE_EVENTS:
from ptrace.binding.func import (WPTRACEEVENT, # noqa
PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK, PTRACE_EVENT_CLONE,
PTRACE_EVENT_EXEC,
ptrace_setoptions, ptrace_geteventmsg)
if HAS_PTRACE_SINGLESTEP:
from ptrace.binding.func import ptrace_singlestep # noqa
if HAS_PTRACE_SIGINFO:
from ptrace.binding.func import ptrace_getsiginfo # noqa
if HAS_PTRACE_IO:
from ptrace.binding.func import ptrace_io # noqa
from ptrace.binding.freebsd_struct import ( # noqa
ptrace_io_desc,
PIOD_READ_D, PIOD_WRITE_D,
PIOD_READ_I, PIOD_WRITE_I)
if HAS_PTRACE_GETREGS:
from ptrace.binding.func import ptrace_getregs # noqa
python-ptrace-0.9.3/ptrace/binding/openbsd_struct.py 0000664 0001750 0001750 00000001615 13047323111 023102 0 ustar haypo haypo 0000000 0000000 from ctypes import Structure, c_int, c_uint, c_ulong, c_void_p, c_char
PIOD_READ_D = 1
PIOD_WRITE_D = 2
PIOD_READ_I = 3
PIOD_WRITE_I = 4
size_t = c_ulong
pid_t = c_int
# /usr/include/machine/reg.h
class reg(Structure):
_fields_ = (
("eax", c_uint),
("ecx", c_uint),
("edx", c_uint),
("ebx", c_uint),
("esp", c_uint),
("ebp", c_uint),
("esi", c_uint),
("edi", c_uint),
("eip", c_uint),
("eflags", c_uint),
("cs", c_uint),
("ss", c_uint),
("ds", c_uint),
("es", c_uint),
("fs", c_uint),
("gs", c_uint),
)
class fpreg(Structure):
_fields_ = (
("__data", c_char * 116),
)
class ptrace_io_desc(Structure):
_fields_ = (
("piod_op", c_int),
("piod_offs", c_void_p),
("piod_addr", c_void_p),
("piod_len", size_t),
)
python-ptrace-0.9.3/ptrace/binding/cpu.py 0000664 0001750 0001750 00000003751 13047323111 020636 0 ustar haypo haypo 0000000 0000000 from ptrace.cpu_info import (
CPU_POWERPC, CPU_INTEL, CPU_X86_64, CPU_I386, CPU_ARM)
CPU_INSTR_POINTER = None
CPU_STACK_POINTER = None
CPU_FRAME_POINTER = None
CPU_SUB_REGISTERS = {}
if CPU_POWERPC:
CPU_INSTR_POINTER = "nip"
# FIXME: Is it the right register?
CPU_STACK_POINTER = 'gpr1'
elif CPU_ARM:
CPU_INSTR_POINTER = 'r15'
CPU_STACK_POINTER = 'r14'
CPU_FRAME_POINTER = 'r11'
elif CPU_X86_64:
CPU_INSTR_POINTER = "rip"
CPU_STACK_POINTER = "rsp"
CPU_FRAME_POINTER = "rbp"
CPU_SUB_REGISTERS = {
# main register name, shift, mask
'al': ('rax', 0, 0xff),
'bl': ('rbx', 0, 0xff),
'cl': ('rcx', 0, 0xff),
'dl': ('rdx', 0, 0xff),
'ah': ('rax', 8, 0xff),
'bh': ('rbx', 8, 0xff),
'ch': ('rcx', 8, 0xff),
'dh': ('rdx', 8, 0xff),
'ax': ('rax', 0, 0xffff),
'bx': ('rbx', 0, 0xffff),
'cx': ('rcx', 0, 0xffff),
'dx': ('rdx', 0, 0xffff),
'eax': ('rax', 32, None),
'ebx': ('rbx', 32, None),
'ecx': ('rcx', 32, None),
'edx': ('rdx', 32, None),
}
elif CPU_I386:
CPU_INSTR_POINTER = "eip"
CPU_STACK_POINTER = "esp"
CPU_FRAME_POINTER = "ebp"
CPU_SUB_REGISTERS = {
'al': ('eax', 0, 0xff),
'bl': ('ebx', 0, 0xff),
'cl': ('ecx', 0, 0xff),
'dl': ('edx', 0, 0xff),
'ah': ('eax', 8, 0xff),
'bh': ('ebx', 8, 0xff),
'ch': ('ecx', 8, 0xff),
'dh': ('edx', 8, 0xff),
'ax': ('eax', 0, 0xffff),
'bx': ('ebx', 0, 0xffff),
'cx': ('ecx', 0, 0xffff),
'dx': ('edx', 0, 0xffff),
}
if CPU_INTEL:
CPU_SUB_REGISTERS.update({
'cf': ('eflags', 0, 1),
'pf': ('eflags', 2, 1),
'af': ('eflags', 4, 1),
'zf': ('eflags', 6, 1),
'sf': ('eflags', 7, 1),
'tf': ('eflags', 8, 1),
'if': ('eflags', 9, 1),
'df': ('eflags', 10, 1),
'of': ('eflags', 11, 1),
'iopl': ('eflags', 12, 2),
})
python-ptrace-0.9.3/ptrace/binding/linux_struct.py 0000664 0001750 0001750 00000013116 13047323324 022614 0 ustar haypo haypo 0000000 0000000 from ctypes import (Structure, Union, sizeof,
c_char, c_ushort, c_int, c_uint, c_ulong, c_void_p,
c_uint16, c_uint32, c_uint64)
from ptrace.cpu_info import CPU_64BITS, CPU_PPC32, CPU_ARM
pid_t = c_int
uid_t = c_ushort
clock_t = c_uint
# From /usr/include/asm-i386/user.h
class user_regs_struct(Structure):
if CPU_PPC32:
_fields_ = (
("gpr0", c_ulong),
("gpr1", c_ulong),
("gpr2", c_ulong),
("gpr3", c_ulong),
("gpr4", c_ulong),
("gpr5", c_ulong),
("gpr6", c_ulong),
("gpr7", c_ulong),
("gpr8", c_ulong),
("gpr9", c_ulong),
("gpr10", c_ulong),
("gpr11", c_ulong),
("gpr12", c_ulong),
("gpr13", c_ulong),
("gpr14", c_ulong),
("gpr15", c_ulong),
("gpr16", c_ulong),
("gpr17", c_ulong),
("gpr18", c_ulong),
("gpr19", c_ulong),
("gpr20", c_ulong),
("gpr21", c_ulong),
("gpr22", c_ulong),
("gpr23", c_ulong),
("gpr24", c_ulong),
("gpr25", c_ulong),
("gpr26", c_ulong),
("gpr27", c_ulong),
("gpr28", c_ulong),
("gpr29", c_ulong),
("gpr30", c_ulong),
("gpr31", c_ulong),
("nip", c_ulong),
("msr", c_ulong),
("orig_gpr3", c_ulong),
("ctr", c_ulong),
("link", c_ulong),
("xer", c_ulong),
("ccr", c_ulong),
("mq", c_ulong), # FIXME: ppc64 => softe
("trap", c_ulong),
("dar", c_ulong),
("dsisr", c_ulong),
("result", c_ulong),
)
elif CPU_ARM:
_fields_ = tuple(("r%i" % reg, c_ulong) for reg in range(18))
elif CPU_64BITS:
_fields_ = (
("r15", c_ulong),
("r14", c_ulong),
("r13", c_ulong),
("r12", c_ulong),
("rbp", c_ulong),
("rbx", c_ulong),
("r11", c_ulong),
("r10", c_ulong),
("r9", c_ulong),
("r8", c_ulong),
("rax", c_ulong),
("rcx", c_ulong),
("rdx", c_ulong),
("rsi", c_ulong),
("rdi", c_ulong),
("orig_rax", c_ulong),
("rip", c_ulong),
("cs", c_ulong),
("eflags", c_ulong),
("rsp", c_ulong),
("ss", c_ulong),
("fs_base", c_ulong),
("gs_base", c_ulong),
("ds", c_ulong),
("es", c_ulong),
("fs", c_ulong),
("gs", c_ulong)
)
else:
_fields_ = (
("ebx", c_ulong),
("ecx", c_ulong),
("edx", c_ulong),
("esi", c_ulong),
("edi", c_ulong),
("ebp", c_ulong),
("eax", c_ulong),
("ds", c_ushort),
("__ds", c_ushort),
("es", c_ushort),
("__es", c_ushort),
("fs", c_ushort),
("__fs", c_ushort),
("gs", c_ushort),
("__gs", c_ushort),
("orig_eax", c_ulong),
("eip", c_ulong),
("cs", c_ushort),
("__cs", c_ushort),
("eflags", c_ulong),
("esp", c_ulong),
("ss", c_ushort),
("__ss", c_ushort),
)
class user_fpregs_struct(Structure):
if CPU_64BITS:
_fields_ = (
("cwd", c_uint16),
("swd", c_uint16),
("ftw", c_uint16),
("fop", c_uint16),
("rip", c_uint64),
("rdp", c_uint64),
("mxcsr", c_uint32),
("mxcr_mask", c_uint32),
("st_space", c_uint32 * 32),
("xmm_space", c_uint32 * 64),
("padding", c_uint32 * 24)
)
else:
_fields_ = (
("cwd", c_ulong),
("swd", c_ulong),
("twd", c_ulong),
("fip", c_ulong),
("fcs", c_ulong),
("foo", c_ulong),
("fos", c_ulong),
("st_space", c_ulong * 20)
)
if not CPU_64BITS:
class user_fpxregs_struct(Structure):
_fields_ = (
("cwd", c_ushort),
("swd", c_ushort),
("twd", c_ushort),
("fop", c_ushort),
("fip", c_ulong),
("fcs", c_ulong),
("foo", c_ulong),
("fos", c_ulong),
("mxcsr", c_ulong),
("reserved", c_ulong),
("st_space", c_ulong * 32),
("xmm_space", c_ulong * 32),
("padding", c_ulong * 56)
)
# From /usr/include/asm-generic/siginfo.h
class _sifields_sigfault_t(Union):
_fields_ = (
("_addr", c_void_p),
)
class _sifields_sigchld_t(Structure):
_fields_ = (
("pid", pid_t),
("uid", uid_t),
("status", c_int),
("utime", clock_t),
("stime", clock_t),
)
class _sifields_t(Union):
_fields_ = (
("pad", c_char * (128 - 3 * sizeof(c_int))),
("_sigchld", _sifields_sigchld_t),
("_sigfault", _sifields_sigfault_t),
# ("_kill", _sifields_kill_t),
# ("_timer", _sifields_timer_t),
# ("_rt", _sifields_rt_t),
# ("_sigpoll", _sifields_sigpoll_t),
)
class siginfo(Structure):
_fields_ = (
("si_signo", c_int),
("si_errno", c_int),
("si_code", c_int),
("_sifields", _sifields_t)
)
_anonymous_ = ("_sifields",)
python-ptrace-0.9.3/ptrace/binding/func.py 0000664 0001750 0001750 00000020052 13047323324 021001 0 ustar haypo haypo 0000000 0000000 from os import strerror
from ctypes import addressof, c_int, get_errno, set_errno
from ptrace import PtraceError
from ptrace.ctypes_tools import formatAddress
from ptrace.os_tools import RUNNING_LINUX, RUNNING_BSD, RUNNING_OPENBSD
from ptrace.cpu_info import CPU_64BITS, CPU_WORD_SIZE, CPU_POWERPC
if RUNNING_OPENBSD:
from ptrace.binding.openbsd_struct import (
reg as ptrace_registers_t,
fpreg as user_fpregs_struct)
elif RUNNING_BSD:
from ptrace.binding.freebsd_struct import (
reg as ptrace_registers_t)
elif RUNNING_LINUX:
from ptrace.binding.linux_struct import (
user_regs_struct as ptrace_registers_t,
user_fpregs_struct, siginfo)
if not CPU_64BITS:
from ptrace.binding.linux_struct import user_fpxregs_struct
else:
raise NotImplementedError("Unknown OS!")
REGISTER_NAMES = tuple(name for name, type in ptrace_registers_t._fields_)
HAS_PTRACE_SINGLESTEP = True
HAS_PTRACE_EVENTS = False
HAS_PTRACE_IO = False
HAS_PTRACE_SIGINFO = False
HAS_PTRACE_GETREGS = False
# Special flags that are required to wait for cloned processes (threads)
# See wait(2)
THREAD_TRACE_FLAGS = 0x00000000
pid_t = c_int
# PTRACE_xxx constants from /usr/include/sys/ptrace.h
# (Linux 2.6.21 Ubuntu Feisty i386)
PTRACE_TRACEME = 0
PTRACE_PEEKTEXT = 1
PTRACE_PEEKDATA = 2
PTRACE_PEEKUSER = 3
PTRACE_POKETEXT = 4
PTRACE_POKEDATA = 5
PTRACE_POKEUSER = 6
PTRACE_CONT = 7
PTRACE_KILL = 8
if HAS_PTRACE_SINGLESTEP:
PTRACE_SINGLESTEP = 9
if RUNNING_OPENBSD:
# OpenBSD 4.2 i386
PTRACE_ATTACH = 9
PTRACE_DETACH = 10
HAS_PTRACE_GETREGS = True
PTRACE_GETREGS = 33
PTRACE_SETREGS = 34
PTRACE_GETFPREGS = 35
PTRACE_SETFPREGS = 36
HAS_PTRACE_IO = True
PTRACE_IO = 11
HAS_PTRACE_SINGLESTEP = True
PTRACE_SINGLESTEP = 32 # PT_STEP
# HAS_PTRACE_EVENTS = True
# PTRACE_SETOPTIONS = 12 # PT_SET_EVENT_MASK
# PTRACE_GETEVENTMSG = 14 # PT_GET_PROCESS_STATE
elif RUNNING_BSD:
# FreeBSD 7.0RC1 i386
PTRACE_ATTACH = 10
PTRACE_DETACH = 11
PTRACE_SYSCALL = 22
if not CPU_POWERPC:
HAS_PTRACE_GETREGS = True
PTRACE_GETREGS = 33
PTRACE_SETREGS = 34
HAS_PTRACE_IO = True
PTRACE_IO = 12
else:
# Linux
HAS_PTRACE_GETREGS = True
PTRACE_GETREGS = 12
PTRACE_SETREGS = 13
PTRACE_ATTACH = 16
PTRACE_DETACH = 17
PTRACE_SYSCALL = 24
if RUNNING_LINUX:
PTRACE_GETFPREGS = 14
PTRACE_SETFPREGS = 15
if not CPU_64BITS:
PTRACE_GETFPXREGS = 18
PTRACE_SETFPXREGS = 19
HAS_PTRACE_SIGINFO = True
PTRACE_GETSIGINFO = 0x4202
PTRACE_SETSIGINFO = 0x4203
HAS_PTRACE_EVENTS = True
PTRACE_SETOPTIONS = 0x4200
PTRACE_GETEVENTMSG = 0x4201
# Linux introduces the __WALL flag for wait
THREAD_TRACE_FLAGS = 0x40000000
PTRACE_O_TRACESYSGOOD = 0x00000001
PTRACE_O_TRACEFORK = 0x00000002
PTRACE_O_TRACEVFORK = 0x00000004
PTRACE_O_TRACECLONE = 0x00000008
PTRACE_O_TRACEEXEC = 0x00000010
PTRACE_O_TRACEVFORKDONE = 0x00000020
PTRACE_O_TRACEEXIT = 0x00000040
# Wait extended result codes for the above trace options
PTRACE_EVENT_FORK = 1
PTRACE_EVENT_VFORK = 2
PTRACE_EVENT_CLONE = 3
PTRACE_EVENT_EXEC = 4
PTRACE_EVENT_VFORK_DONE = 5
PTRACE_EVENT_EXIT = 6
try:
from cptrace import ptrace as _ptrace
HAS_CPTRACE = True
except ImportError:
HAS_CPTRACE = False
from ctypes import c_long, c_ulong
from ptrace.ctypes_libc import libc
# Load ptrace() function from the system C library
_ptrace = libc.ptrace
_ptrace.argtypes = (c_ulong, c_ulong, c_ulong, c_ulong)
_ptrace.restype = c_ulong
def ptrace(command, pid=0, arg1=0, arg2=0, check_errno=False):
if HAS_CPTRACE:
try:
set_errno(0)
result = _ptrace(command, pid, arg1, arg2, check_errno)
except ValueError as errobj:
message = str(errobj)
errno = get_errno()
raise PtraceError(message, errno=errno, pid=pid)
else:
result = _ptrace(command, pid, arg1, arg2)
result_signed = c_long(result).value
if result_signed == -1:
errno = get_errno()
# peek operations may returns -1 with errno=0:
# it's not an error. For other operations, -1
# is always an error
if not(check_errno) or errno:
message = "ptrace(cmd=%s, pid=%s, %r, %r) error #%s: %s" % (
command, pid, arg1, arg2,
errno, strerror(errno))
raise PtraceError(message, errno=errno, pid=pid)
return result
def ptrace_traceme():
ptrace(PTRACE_TRACEME)
def ptrace_attach(pid):
ptrace(PTRACE_ATTACH, pid)
def ptrace_detach(pid, signal=0):
ptrace(PTRACE_DETACH, pid, 0, signal)
def _peek(command, pid, address):
if address % CPU_WORD_SIZE:
raise PtraceError(
"ptrace can't read a word from an unaligned address (%s)!"
% formatAddress(address), pid=pid)
return ptrace(command, pid, address, check_errno=True)
def _poke(command, pid, address, word):
if address % CPU_WORD_SIZE:
raise PtraceError(
"ptrace can't write a word to an unaligned address (%s)!"
% formatAddress(address), pid=pid)
ptrace(command, pid, address, word)
def ptrace_peektext(pid, address):
return _peek(PTRACE_PEEKTEXT, pid, address)
def ptrace_peekdata(pid, address):
return _peek(PTRACE_PEEKDATA, pid, address)
def ptrace_peekuser(pid, address):
return _peek(PTRACE_PEEKUSER, pid, address)
def ptrace_poketext(pid, address, word):
_poke(PTRACE_POKETEXT, pid, address, word)
def ptrace_pokedata(pid, address, word):
_poke(PTRACE_POKEDATA, pid, address, word)
def ptrace_pokeuser(pid, address, word):
_poke(PTRACE_POKEUSER, pid, address, word)
def ptrace_kill(pid):
ptrace(PTRACE_KILL, pid)
if HAS_PTRACE_EVENTS:
def WPTRACEEVENT(status):
return status >> 16
def ptrace_setoptions(pid, options):
ptrace(PTRACE_SETOPTIONS, pid, 0, options)
def ptrace_geteventmsg(pid):
new_pid = pid_t()
ptrace(PTRACE_GETEVENTMSG, pid, 0, addressof(new_pid))
return new_pid.value
if RUNNING_LINUX:
def ptrace_syscall(pid, signum=0):
ptrace(PTRACE_SYSCALL, pid, 0, signum)
def ptrace_cont(pid, signum=0):
ptrace(PTRACE_CONT, pid, 0, signum)
def ptrace_getsiginfo(pid):
info = siginfo()
ptrace(PTRACE_GETSIGINFO, pid, 0, addressof(info))
return info
def ptrace_setsiginfo(pid, info):
ptrace(PTRACE_SETSIGINFO, pid, 0, addressof(info))
def ptrace_getfpregs(pid):
fpregs = user_fpregs_struct()
ptrace(PTRACE_GETFPREGS, pid, 0, addressof(fpregs))
return fpregs
def ptrace_setfpregs(pid, fpregs):
ptrace(PTRACE_SETFPREGS, pid, 0, addressof(fpregs))
if not CPU_64BITS:
def ptrace_getfpxregs(pid):
fpxregs = user_fpxregs_struct()
ptrace(PTRACE_GETFPXREGS, pid, 0, addressof(fpxregs))
return fpxregs
def ptrace_setfpxregs(pid, fpxregs):
ptrace(PTRACE_SETFPXREGS, pid, 0, addressof(fpxregs))
if HAS_PTRACE_GETREGS:
def ptrace_getregs(pid):
regs = ptrace_registers_t()
ptrace(PTRACE_GETREGS, pid, 0, addressof(regs))
return regs
def ptrace_setregs(pid, regs):
ptrace(PTRACE_SETREGS, pid, 0, addressof(regs))
if HAS_PTRACE_SINGLESTEP:
def ptrace_singlestep(pid):
ptrace(PTRACE_SINGLESTEP, pid)
else:
def ptrace_syscall(pid, signum=0):
ptrace(PTRACE_SYSCALL, pid, 1, signum)
def ptrace_cont(pid, signum=0):
ptrace(PTRACE_CONT, pid, 1, signum)
if HAS_PTRACE_GETREGS:
def ptrace_getregs(pid):
regs = ptrace_registers_t()
ptrace(PTRACE_GETREGS, pid, addressof(regs))
return regs
def ptrace_setregs(pid, regs):
ptrace(PTRACE_SETREGS, pid, addressof(regs))
if HAS_PTRACE_SINGLESTEP:
def ptrace_singlestep(pid):
ptrace(PTRACE_SINGLESTEP, pid, 1)
if HAS_PTRACE_IO:
def ptrace_io(pid, io_desc):
ptrace(PTRACE_IO, pid, addressof(io_desc))
python-ptrace-0.9.3/ptrace/binding/freebsd_struct.py 0000664 0001750 0001750 00000003733 13047323113 023067 0 ustar haypo haypo 0000000 0000000 from ctypes import (Structure,
c_int, c_uint, c_ulong, c_void_p,
c_uint16, c_uint32, c_size_t)
from ptrace.cpu_info import CPU_X86_64
PIOD_READ_D = 1
PIOD_WRITE_D = 2
PIOD_READ_I = 3
PIOD_WRITE_I = 4
# /usr/include/machine/reg.h
if CPU_X86_64:
register_t = c_ulong
class reg(Structure):
_fields_ = (
("r15", register_t),
("r14", register_t),
("r13", register_t),
("r12", register_t),
("r11", register_t),
("r10", register_t),
("r9", register_t),
("r8", register_t),
("rdi", register_t),
("rsi", register_t),
("rbp", register_t),
("rbx", register_t),
("rdx", register_t),
("rcx", register_t),
("rax", register_t),
("trapno", c_uint32),
("fs", c_uint16),
("gs", c_uint16),
("err", c_uint32),
("es", c_uint16),
("ds", c_uint16),
("rip", register_t),
("cs", register_t),
("rflags", register_t),
("rsp", register_t),
("ss", register_t),
)
else:
class reg(Structure):
_fields_ = (
("fs", c_uint),
("es", c_uint),
("ds", c_uint),
("edi", c_uint),
("esi", c_uint),
("ebp", c_uint),
("isp", c_uint),
("ebx", c_uint),
("edx", c_uint),
("ecx", c_uint),
("eax", c_uint),
("trapno", c_uint),
("err", c_uint),
("eip", c_uint),
("cs", c_uint),
("eflags", c_uint),
("esp", c_uint),
("ss", c_uint),
("gs", c_uint),
)
class ptrace_io_desc(Structure):
_fields_ = (
("piod_op", c_int),
("piod_offs", c_void_p),
("piod_addr", c_void_p),
("piod_len", c_size_t),
)
python-ptrace-0.9.3/ptrace/error.py 0000664 0001750 0001750 00000003515 13047323112 017565 0 ustar haypo haypo 0000000 0000000 from sys import exc_info
from traceback import format_exception
from logging import ERROR, getLogger
from ptrace.logging_tools import getLogFunc, changeLogLevel
PTRACE_ERRORS = Exception
def writeBacktrace(logger, log_level=ERROR):
"""
Write a backtrace into the logger with the specified log level.
"""
log_func = getLogFunc(logger, log_level)
try:
info = exc_info()
trace = format_exception(*info)
if trace[0] != "None\n":
trace = ''.join(trace).rstrip()
for line in trace.split("\n"):
log_func(line.rstrip())
return
except:
pass
log_func("Unable to get backtrace")
def formatError(error):
"""
Format an error as a string. Write the error type as prefix.
Eg. "[ValueError] invalid value".
"""
return "[%s] %s" % (error.__class__.__name__, error)
def writeError(logger, error, title="ERROR", log_level=ERROR):
"""
Write an error into the logger:
- logger: the logger (if None, use getLogger())
- error: the exception object
- title: error message prefix (e.g. title="Initialization error")
- log_level: log level of the error
If the exception is a SystemExit or a KeyboardInterrupt, re-emit
(raise) the exception and don't write it.
"""
if not logger:
logger = getLogger()
if error.__class__ in (SystemExit, KeyboardInterrupt):
raise error
log_func = getLogFunc(logger, log_level)
log_func("%s: %s" % (title, formatError(error)))
writeBacktrace(logger, log_level=changeLogLevel(log_level, -1))
class PtraceError(Exception):
"""
Ptrace error: have the optional attributes errno and pid.
"""
def __init__(self, message, errno=None, pid=None):
Exception.__init__(self, message)
self.errno = errno
self.pid = pid
python-ptrace-0.9.3/ptrace/linux_proc.py 0000664 0001750 0001750 00000014237 13047323324 020626 0 ustar haypo haypo 0000000 0000000 """
Functions and variables to access to Linux proc directory.
Constant:
- PAGE_SIZE: size of a memory page
"""
from __future__ import with_statement
from os import readlink, listdir
from resource import getpagesize
from ptrace.tools import timestampUNIX
from datetime import timedelta
PAGE_SIZE = getpagesize()
class ProcError(Exception):
"""
Linux proc directory error.
"""
pass
def openProc(path):
"""
Open a proc entry in read only mode.
"""
filename = "/proc/%s" % path
try:
return open(filename)
except IOError as err:
raise ProcError("Unable to open %r: %s" % (filename, err))
def readProc(path):
"""
Read the content of a proc entry.
Eg. readProc("stat") to read /proc/stat.
"""
with openProc(path) as procfile:
return procfile.read()
def readProcessProc(pid, key):
"""
Read the content of a process entry in the proc directory.
Eg. readProcessProc(pid, "status") to read /proc/pid/status.
"""
try:
filename = "/proc/%s/%s" % (pid, key)
with open(filename) as proc:
return proc.read()
except IOError as err:
raise ProcError("Process %s doesn't exist: %s" % (pid, err))
class ProcessState(object):
"""
Processus state. Attributes:
- state (str): process status ('R', 'S', 'T', ...)
- program (str): program name
- pid (int): process identifier
- ppid (int): parent process identifier
- pgrp (int): process group
- session (int): session identifier
- tty_nr (int): tty number
- tpgid (int)
- utime (int): user space time (jiffies)
- stime (int): kernel space time (jiffies)
- starttime (int): start time
"""
STATE_NAMES = {
"R": "running",
"S": "sleeping",
"D": "disk",
"Z": "zombie",
"T": "traced",
"W": "paging",
}
def __init__(self, stat):
# pid (program) ... => "pid (program", "..."
part, stat = stat.rsplit(')', 1)
self.pid, self.program = part.split('(', 1)
self.pid = int(self.pid)
# "state ..." => state, "..."
stat = stat.split()
self.state = stat[0]
stat = [int(item) for item in stat[1:]]
# Read next numbers
self.ppid = stat[0]
self.pgrp = stat[1]
self.session = stat[2]
self.tty_nr = stat[3]
self.tpgid = stat[4]
self.utime = stat[10]
self.stime = stat[11]
self.starttime = stat[18]
def readProcessStat(pid):
"""
Read the process state ('stat') as a ProcessState object.
"""
stat = readProcessProc(pid, 'stat')
return ProcessState(stat)
def readProcessStatm(pid):
"""
Read the process memory status ('statm') as a list of integers.
Values are in bytes (and not in pages).
"""
statm = readProcessProc(pid, 'statm')
statm = [int(item) * PAGE_SIZE for item in statm.split()]
return statm
def readProcessProcList(pid, key):
"""
Read a process entry as a list of strings.
"""
data = readProcessProc(pid, key)
if not data:
# Empty file: empty list
return []
data = data.split("\0")
if not data[-1]:
del data[-1]
return data
def readProcessLink(pid, key):
"""
Read a process link.
"""
try:
filename = "/proc/%s/%s" % (pid, key)
return readlink(filename)
except OSError as err:
raise ProcError("Unable to read proc link %r: %s" % (filename, err))
def readProcesses():
"""
Read all processes identifiers. The function is a generator,
use it with: ::
for pid in readProcesses(): ...
"""
for filename in listdir('/proc'):
try:
yield int(filename)
except ValueError:
# Filename is not an integer (e.g. "stat" from /proc/stat)
continue
def readProcessCmdline(pid, escape_stat=True):
"""
Read the process command line. If escape_stat is True, format program name
with "[%s]" if the process has no command line, e.g. "[khelper]".
"""
# Try /proc/42/cmdline
try:
cmdline = readProcessProcList(pid, 'cmdline')
if cmdline:
return cmdline
except ProcError:
pass
# Try /proc/42/stat
try:
stat = readProcessStat(pid)
program = stat.program
if escape_stat:
program = "[%s]" % program
return [program]
except ProcError:
return None
def searchProcessesByName(process_name):
"""
Find all processes matching the program name pattern.
Eg. pattern "ssh" will find the program "/usr/bin/ssh".
This function is a generator yielding the process identifier,
use it with: ::
for pid in searchProcessByName(pattern):
...
"""
suffix = '/' + process_name
for pid in readProcesses():
cmdline = readProcessCmdline(pid)
if not cmdline:
continue
program = cmdline[0]
if program == process_name or program.endswith(suffix):
yield pid
def searchProcessByName(process_name):
"""
Function similar to searchProcessesByName() but only return the identifier
of the first matching process. Raise a ProcError if there is no matching
process.
"""
for pid in searchProcessesByName(process_name):
return pid
raise ProcError("Unable to find process: %r" % process_name)
def getUptime():
"""
Get the system uptime as a datetime.timedelta object.
"""
uptime = readProc('uptime')
uptime = uptime.strip().split()
uptime = float(uptime[0])
return timedelta(seconds=uptime)
def getSystemBoot():
"""
Get the system boot date as a datetime.datetime object.
"""
if getSystemBoot.value is None:
stat_file = openProc('stat')
for line in stat_file:
if not line.startswith("btime "):
continue
seconds = int(line[6:])
btime = timestampUNIX(seconds, True)
getSystemBoot.value = btime
break
stat_file.close()
if getSystemBoot.value is None:
raise ProcError("Unable to read system boot time!")
return getSystemBoot.value
getSystemBoot.value = None
python-ptrace-0.9.3/ptrace/ctypes_tools.py 0000664 0001750 0001750 00000007611 13047323324 021171 0 ustar haypo haypo 0000000 0000000 from struct import pack, unpack
from ptrace.cpu_info import CPU_64BITS
from ctypes import cast, POINTER
def int2uint64(value):
"""
Convert a signed 64 bits integer into an unsigned 64 bits integer.
>>> print(int2uint64(1))
1
>>> print(int2uint64(2**64 + 1)) # ignore bits larger than 64 bits
1
>>> print(int2uint64(-1))
18446744073709551615
>>> print(int2uint64(-2))
18446744073709551614
"""
return (value & 0xffffffffffffffff)
def uint2int64(value):
"""
Convert an unsigned 64 bits integer into a signed 64 bits integer.
>>> print(uint2int64(1))
1
>>> print(uint2int64(2**64 + 1)) # ignore bits larger than 64 bits
1
>>> print(uint2int64(18446744073709551615))
-1
>>> print(uint2int64(18446744073709551614))
-2
"""
value = value & 0xffffffffffffffff
if value & 0x8000000000000000:
return value - 0x10000000000000000
else:
return value
def truncateWord32(value):
"""
Truncate an unsigned integer to 32 bits.
"""
return value & 0xFFFFFFFF
def truncateWord64(value):
"""
Truncate an unsigned integer to 64 bits.
"""
return value & 0xFFFFFFFFFFFFFFFF
def formatUintHex16(value):
"""
Format an 16 bits unsigned integer.
"""
return u"0x%04x" % value
def formatUintHex32(value):
"""
Format an 32 bits unsigned integer.
"""
return u"0x%08x" % value
def formatUintHex64(value):
"""
Format an 64 bits unsigned integer.
"""
return u"0x%016x" % value
def int2uint32(value):
"""
Convert a signed 32 bits integer into an unsigned 32 bits integer.
>>> print(int2uint32(1))
1
>>> print(int2uint32(2**32 + 1)) # ignore bits larger than 32 bits
1
>>> print(int2uint32(-1))
4294967295
"""
return value & 0xffffffff
def uint2int32(value):
"""
Convert an unsigned 32 bits integer into a signed 32 bits integer.
>>> print(uint2int32(1))
1
>>> print(uint2int32(2**32 + 1)) # ignore bits larger than 32 bits
1
>>> print(uint2int32(4294967295))
-1
>>> print(uint2int32(4294967294))
-2
>>> print(uint2int32(18446744073709551615))
-1
"""
value = value & 0xffffffff
if value & 0x80000000:
v = value - 0x100000000
else:
v = value
return v
uint2int = uint2int32
int2uint = int2uint32
if CPU_64BITS:
ulong2long = uint2int64
long2ulong = int2uint64
formatWordHex = formatUintHex64
truncateWord = truncateWord64
else:
ulong2long = uint2int32
long2ulong = int2uint32
formatWordHex = formatUintHex32
truncateWord = truncateWord32
def formatAddress(address):
"""
Format an address to hexadecimal.
Return "NULL" for zero.
"""
if address:
return formatWordHex(address)
else:
return u"NULL"
def formatAddressRange(start, end):
"""
Format an address range, e.g. "0x80004000-0x8000ffff".
"""
return u"%s-%s" % (formatWordHex(start), formatWordHex(end))
def ntoh_ushort(value):
"""
Convert an unsigned short integer from network endian to host endian.
"""
return unpack("H", value))[0]
def ntoh_uint(value):
"""
Convert an unsigned integer from network endian to host endian.
"""
return unpack("I", value))[0]
def word2bytes(word):
"""
Convert an unsigned integer (a CPU word) to a bytes string.
"""
return pack("L", word)
def bytes2word(bytes):
"""
Convert a bytes string to an unsigned integer (a CPU word).
"""
return unpack("L", bytes)[0]
def bytes2type(bytes, type):
"""
Cast a bytes string to an object of the specified type.
"""
return cast(bytes, POINTER(type))[0]
def bytes2array(bytes, basetype, size):
"""
Cast a bytes string to an array of objects of the specified type
and size.
"""
return bytes2type(bytes, basetype * size)
python-ptrace-0.9.3/examples/ 0000775 0001750 0001750 00000000000 13160156527 016430 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/examples/simple_dbg.py 0000775 0001750 0001750 00000003162 13047321200 021076 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
from ptrace.debugger.debugger import PtraceDebugger
from ptrace.debugger.child import createChild
from ptrace.tools import locateProgram
from sys import stderr, argv, exit
def playWithProcess(process):
# Do anything you want with the process here...
print("Dump process registers")
process.dumpRegs()
print("Continue process execution")
process.cont()
print("Wait next process event...")
event = process.waitEvent()
print("New process event: %s" % event)
def traceProgram(arguments):
# Copy the environment variables
env = None
# Get the full path of the program
arguments[0] = locateProgram(arguments[0])
# Create the child process
return createChild(arguments, False, env)
def main():
# Check the command line
if len(argv) < 2:
print("usage: %s program [arg1 arg2 ...]" % argv[0], file=stderr)
print(" or: %s pid" % argv[0], file=stderr)
exit(1)
# Get the process identifier
is_attached = False
has_pid = False
if len(argv) == 2:
try:
# User asked to attach a process
pid = int(argv[1])
has_pid = True
except ValueError:
pass
if not has_pid:
# User asked to create a new program and trace it
arguments = argv[1:]
pid = traceProgram(arguments)
is_attached = True
# Create the debugger and attach the process
dbg = PtraceDebugger()
process = dbg.addProcess(pid, is_attached)
# Play with the process and then quit
playWithProcess(process)
dbg.quit()
if __name__ == "__main__":
main()
python-ptrace-0.9.3/examples/itrace.py 0000775 0001750 0001750 00000003356 13047321200 020245 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
"""
Here is a tool which I have been using to debug libc startup code where I
didn't find gdb very helpful. It single steps the process and prints each
instruction pointer address. To go faster, it allows a number of syscalls to
run before starting single-stepping.
It's possible to pipe the addresses through addr2line to get a very
simple tracing debugger. :-)
I couldn't see a way to catch syscalls and single step at the same
time. As a consequence the tool can't handle multiple threads.
Mark
"""
import signal
from ptrace.debugger import ProcessExit, ProcessSignal
import strace
class Tracer(strace.SyscallTracer):
def createCommonOptions(self, parser):
parser.add_option(
"-n", dest="syscall_limit", type="int", default=None,
help="Number of syscalls before switching to single step")
super(Tracer, self).createCommonOptions(parser)
def syscallTrace(self, process):
syscall_limit = self.options.syscall_limit
i = 0
while i < syscall_limit or syscall_limit is None:
print(i)
i += 1
process.syscall()
self.debugger.waitSyscall()
i = 0
while self.debugger:
eip = process.getInstrPointer()
print(i, process.pid, "[%08x]" % eip)
i += 1
process.singleStep()
event = self.debugger.waitProcessEvent()
if isinstance(event, ProcessExit):
print("process exit")
return
if (isinstance(event, ProcessSignal) and
event.signum & ~128 != signal.SIGTRAP):
print("died with signal %i" % event.signum)
return
if __name__ == "__main__":
Tracer().main()
python-ptrace-0.9.3/README.rst 0000664 0001750 0001750 00000001503 13047321200 016262 0 ustar haypo haypo 0000000 0000000 =============
python-ptrace
=============
.. image:: https://img.shields.io/pypi/v/python-ptrace.svg
:alt: Latest release on the Python Cheeseshop (PyPI)
:target: https://pypi.python.org/pypi/python-ptrace
.. image:: https://travis-ci.org/haypo/python-ptrace.svg?branch=master
:alt: Build status of python-ptrace on Travis CI
:target: https://travis-ci.org/haypo/python-ptrace
python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to
trace processes) written in Python.
* `python-ptrace documentation
`_
* `python-ptrace at GitHub
`_
* `python-ptrace at the Python Cheeseshop (PyPI)
`_
python-ptrace is an opensource project written in Python under GNU GPLv2
license.
python-ptrace-0.9.3/MANIFEST.in 0000664 0001750 0001750 00000001057 13047321200 016335 0 ustar haypo haypo 0000000 0000000 include AUTHORS
include COPYING
include ChangeLog
include INSTALL
include MANIFEST.in
include README.cptrace
include TODO
include tox.ini
include cptrace/Makefile
include cptrace/cptrace.c
include cptrace/version.py
include doc/*.rst doc/conf.py doc/make.bat doc/Makefile
include examples/itrace.py
include examples/simple_dbg.py
include pyflakes.sh
include python3.0.patch
include setup_cptrace.py
# Tests
include runtests.py
include test_doc.py
include tests/test_*.py
include tests/crash/*.c
include tests/crash/BSDmakefile
include tests/crash/Makefile
python-ptrace-0.9.3/test_doc.py 0000775 0001750 0001750 00000002303 13047323324 016764 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
from doctest import testfile, ELLIPSIS, testmod
from sys import exit, path as sys_path
from os.path import dirname
def testDoc(filename, name=None):
print("--- %s: Run tests" % filename)
failure, nb_test = testfile(
filename, optionflags=ELLIPSIS, name=name)
if failure:
exit(1)
print("--- %s: End of tests" % filename)
def importModule(name):
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod
def testModule(name):
print("--- Test module %s" % name)
module = importModule(name)
failure, nb_test = testmod(module)
if failure:
exit(1)
print("--- End of test")
def main():
ptrace_dir = dirname(__file__)
sys_path.append(ptrace_dir)
# Test documentation in doc/*.rst files
# testDoc('doc/c_tools.rst')
# Test documentation of some functions/classes
testModule("ptrace.ctypes_tools")
testModule("ptrace.debugger.parse_expr")
testModule("ptrace.logging_tools")
testModule("ptrace.signames")
testModule("ptrace.syscall.socketcall")
testModule("ptrace.tools")
if __name__ == "__main__":
main()
python-ptrace-0.9.3/tests/ 0000775 0001750 0001750 00000000000 13160156527 015754 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/tests/crash/ 0000775 0001750 0001750 00000000000 13160156527 017054 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/tests/crash/invalid_read.c 0000664 0001750 0001750 00000000220 13047321200 021615 0 ustar haypo haypo 0000000 0000000 typedef struct
{
int x;
int y;
int z;
} point_t;
int main()
{
point_t *point = 0;
int z;
z = point->z;
return z;
}
python-ptrace-0.9.3/tests/crash/call_null.c 0000664 0001750 0001750 00000000106 13047321200 021144 0 ustar haypo haypo 0000000 0000000 int main()
{
void (*func) (void) = 0;
func();
return 0;
}
python-ptrace-0.9.3/tests/crash/execve.c 0000664 0001750 0001750 00000000545 13047321200 020465 0 ustar haypo haypo 0000000 0000000 #include
#include
#include
#include
int main()
{
char *arg[]= {"/bin/ls", NULL };
int pid;
pid = fork();
if (pid) {
waitpid(pid, NULL, 0);
exit(EXIT_SUCCESS);
} else {
(void)uname(NULL);
execve(arg[0], arg, NULL);
exit(EXIT_FAILURE);
}
}
python-ptrace-0.9.3/tests/crash/abort.c 0000664 0001750 0001750 00000000076 13047321200 020314 0 ustar haypo haypo 0000000 0000000 #include
int main()
{
abort();
return 0;
}
python-ptrace-0.9.3/tests/crash/pthread.c 0000664 0001750 0001750 00000001013 13047321200 020624 0 ustar haypo haypo 0000000 0000000 #include
#include
#define UNUSED(x) x __attribute__((unused))
pthread_t thread;
pthread_mutex_t mutex;
int global_counter;
void* nothing(void *UNUSED(data))
{
printf("[thread] exit thread\n");
pthread_exit(NULL);
}
int main()
{
global_counter = 1;
printf("[main] create thread\n");
pthread_create(&thread, NULL, nothing, NULL);
printf("[main] join thread\n");
pthread_join(thread, NULL);
printf("[main] exit\n");
pthread_mutex_destroy(&mutex);
return 0;
}
python-ptrace-0.9.3/tests/crash/socket_ipv4_tcp.c 0000664 0001750 0001750 00000001263 13047321200 022304 0 ustar haypo haypo 0000000 0000000 #include
#include /* close() */
#include /* perror() */
#include /* struct sockaddr_in */
int main()
{
int fd;
int val;
int ret;
struct sockaddr_in addr;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0)
perror("socket");
val = 1;
(void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
addr.sin_addr.s_addr = 0x7f000001;
ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if (ret < 0)
perror("connect");
ret = close(fd);
if (ret)
perror("close");
return 0;
}
python-ptrace-0.9.3/tests/crash/Makefile 0000664 0001750 0001750 00000000477 13047321200 020506 0 ustar haypo haypo 0000000 0000000 CC=gcc
SOURCES=stack_overflow.c div_zero.c call_null.c abort.c fork.c execve.c invalid_write.c invalid_read.c socket_ipv4_tcp.c
PROGRAMS=$(patsubst %.c,%,$(SOURCES)) pthread
CFLAGS=-Wall -Wextra -Werror -O0 -g
all: $(PROGRAMS)
pthread: pthread.c
$(CC) -o $@ $(CFLAGS) pthread.c -lpthread
clean:
rm -f $(PROGRAMS)
python-ptrace-0.9.3/tests/crash/stack_overflow.c 0000664 0001750 0001750 00000000252 13047321200 022231 0 ustar haypo haypo 0000000 0000000 char toto()
{
char buffer[4096];
buffer[0] = 0;
toto();
return buffer[0] + buffer[sizeof(buffer)-1];
}
int main()
{
char c = toto();
return c;
}
python-ptrace-0.9.3/tests/crash/BSDmakefile 0000664 0001750 0001750 00000000404 13047321200 021065 0 ustar haypo haypo 0000000 0000000 SOURCES=stack_overflow.c div_zero.c call_null.c abort.c fork.c invalid_write.c invalid_read.c
PROGRAMS=${SOURCES:S/.c//g} pthread
CFLAGS=-Wall -O0 -g
all: $(PROGRAMS)
pthread: pthread.c
$(CC) -o $@ $(CFLAGS) pthread.c -lpthread
clean:
rm -f $(PROGRAMS)
python-ptrace-0.9.3/tests/crash/fork.c 0000664 0001750 0001750 00000002017 13047321200 020143 0 ustar haypo haypo 0000000 0000000 #include
#include
#include
#include
#include
#include
int parent_pid;
void parent(pid_t child_pid)
{
int status;
int result;
printf("[parent:%i] wait for child exit\n", parent_pid);
result = waitpid(child_pid, &status, 0);
if (result != child_pid) {
perror("waitpid");
exit(1);
}
printf("[parent:%i] child exited with status %i\n",
parent_pid, status);
}
void child()
{
struct utsname buf;
int err;
int pid = getpid();
printf("[child:%i] uname()\n", pid);
err = uname(&buf);
if (err) {
perror("uname");
exit(1);
}
printf("[child:%i] done, exit.\n", pid);
}
int main()
{
pid_t pid;
/* fork process */
parent_pid = getpid();
printf("[parent:%i] fork\n", parent_pid);
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid) {
parent(pid);
} else {
child();
}
return 0;
}
python-ptrace-0.9.3/tests/crash/div_zero.c 0000664 0001750 0001750 00000000107 13047321200 021021 0 ustar haypo haypo 0000000 0000000 int main()
{
int x = 1;
int y = 0;
x /= y;
return 0;
}
python-ptrace-0.9.3/tests/crash/invalid_write.c 0000664 0001750 0001750 00000000206 13047321200 022040 0 ustar haypo haypo 0000000 0000000 typedef struct
{
int x;
int y;
int z;
} point_t;
int main()
{
point_t *point = 0;
point->z = 42;
return 0;
}
python-ptrace-0.9.3/tests/test_gdb.py 0000775 0001750 0001750 00000005040 13047323324 020116 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
import os
import re
import subprocess
import sys
import unittest
from ptrace import six
GDB = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', 'gdb.py'))
class TestGdb(unittest.TestCase):
def run_command(self, command):
if isinstance(command, six.text_type):
command = command.encode('ascii')
command = command + b'\n'
args = [sys.executable, GDB, '--', sys.executable, '-c', 'pass']
proc = subprocess.Popen(args,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout, _ = proc.communicate(command)
exitcode = proc.wait()
self.assertEqual(exitcode, 0)
if stdout.startswith(b'(gdb) '):
stdout = stdout[6:]
pos = stdout.rfind(b'(gdb) ')
if pos:
stdout = stdout[:pos]
stdout = stdout.rstrip()
if b'Traceback' in stdout:
self.fail('Traceback in output: %r' % stdout)
return stdout
def check_stdout(self, pattern, stdout):
self.assertTrue(re.search(pattern, stdout, re.MULTILINE),
(pattern, stdout))
def test_proc(self):
stdout = self.run_command('proc')
for pattern in (
b'^Process ID: [0-9]+',
b'^Process state: ',
b'^Process environment: ',
b'^User identifier: [0-9]+',
b'^Group identifier: [0-9]+',
):
self.assertTrue(re.search(pattern, stdout, re.MULTILINE),
(pattern, stdout))
def test_print(self):
stdout = self.run_command('print 1+2')
self.check_stdout(b'^Decimal: 3\n', stdout)
def test_where(self):
stdout = self.run_command('where')
self.check_stdout(b'^CODE: ', stdout)
def test_regs(self):
# Just check that the command doesn't raise an exception
self.run_command('regs')
def test_backtrace(self):
# Just check that the command doesn't raise an exception
self.run_command('backtrace')
def test_maps(self):
stdout = self.run_command('maps')
self.check_stdout(b'^MAPS: ', stdout)
def test_dbginfo(self):
stdout = self.run_command('dbginfo')
self.check_stdout(b'^Debugger process ID: [0-9]+', stdout)
self.check_stdout(b'^python-ptrace version [0-9]+\\.[0-9]+', stdout)
self.check_stdout(b'^Website: ', stdout)
if __name__ == "__main__":
unittest.main()
python-ptrace-0.9.3/tests/test_strace.py 0000775 0001750 0001750 00000006324 13157761310 020654 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
import os
import re
import subprocess
import sys
import tempfile
import unittest
from ptrace import six
STRACE = os.path.normpath(os.path.join(
os.path.dirname(__file__), '..', 'strace.py'))
class TestStrace(unittest.TestCase):
def strace(self, *args):
""" Strace the given command and return the strace output. """
with tempfile.NamedTemporaryFile(mode='wb+') as temp:
args = (sys.executable, STRACE, '-o', temp.name, '--') + args
with open(os.devnull, "wb") as devnull:
proc = subprocess.Popen(args,
stdout=devnull,
stderr=subprocess.STDOUT)
proc.wait()
temp.seek(0)
strace = temp.readlines()
strace = b''.join(strace)
self.assertIsNone(re.match(b'^Traceback', strace), strace)
return strace
def assert_syscall(self, code, regex):
"""
Strace the given python code and match the strace output against the
given regular expression.
"""
stdout = self.strace(sys.executable, '-c', code)
pattern = re.compile(regex, re.MULTILINE)
self.assertTrue(pattern.search(stdout), stdout)
def test_basic(self):
stdout = self.strace(sys.executable, '-c', 'pass')
for syscall in (b'exit', b'mmap', b'open'):
pattern = re.compile(b'^' + syscall, re.MULTILINE)
self.assertTrue(pattern.search(stdout), stdout)
def test_getcwd(self):
cwd = os.getcwd()
stdout = self.strace(sys.executable, '-c', 'import os; os.getcwd()')
pattern = re.compile(b'^getcwd\\((.*),', re.MULTILINE)
match = pattern.search(stdout)
self.assertTrue(match, stdout)
expected = repr(cwd)
if six.PY3:
expected = os.fsencode(expected)
self.assertEqual(match.group(1), expected)
def test_open(self):
if six.PY3:
code = 'open(%a).close()' % __file__
else:
code = 'open(%r).close()' % __file__
self.assert_syscall(code,
br"^open(at)?\(.*test_strace\.pyc?', O_RDONLY(\|O_CLOEXEC)?")
def test_chdir(self):
self.assert_syscall(
"import os; os.chdir('directory')",
br"^chdir\('directory'\)\s+= -2 ENOENT")
def test_rename(self):
self.assert_syscall(
"import os; os.rename('oldpath', 'newpath')",
br"^rename\('oldpath', 'newpath'\)")
def test_link(self):
self.assert_syscall(
"import os; os.link('oldpath', 'newpath')",
br"^link\('oldpath', 'newpath'\)")
def test_symlink(self):
try:
self.assert_syscall(
"import os; os.symlink('target', 'linkpath')",
br"^symlink\('target', 'linkpath'\)")
finally:
try:
os.unlink('linkpath')
except OSError:
pass
def test_socket(self):
self.assert_syscall(
"import socket; socket.socket(socket.AF_INET,socket.SOCK_STREAM).close()",
br'^socket\(AF_INET, SOCK_STREAM(\|SOCK_CLOEXEC)?')
if __name__ == "__main__":
unittest.main()
python-ptrace-0.9.3/COPYING 0000664 0001750 0001750 00000043133 13047321200 015633 0 ustar haypo haypo 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
python-ptrace-0.9.3/setup_cptrace.py 0000775 0001750 0001750 00000002505 13047323324 020025 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
SOURCES = ['cptrace/cptrace.c']
CLASSIFIERS = [
'Intended Audience :: Developers',
'Development Status :: 4 - Beta',
'Environment :: Console',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Operating System :: OS Independent',
'Natural Language :: English',
'Programming Language :: C',
'Programming Language :: Python',
]
LONG_DESCRIPTION = open('doc/cptrace.rst').read()
def main():
from imp import load_source
from os import path
from sys import argv
if "--setuptools" in argv:
argv.remove("--setuptools")
from setuptools import setup, Extension
else:
from distutils.core import setup, Extension
cptrace_ext = Extension('cptrace', sources=SOURCES)
cptrace = load_source("version", path.join("cptrace", "version.py"))
install_options = {
"name": cptrace.PACKAGE,
"version": cptrace.VERSION,
"url": cptrace.WEBSITE,
"download_url": cptrace.WEBSITE,
"license": cptrace.LICENSE,
"author": "Victor Stinner",
"description": "python binding of ptrace written in C",
"long_description": LONG_DESCRIPTION,
"classifiers": CLASSIFIERS,
"ext_modules": [cptrace_ext],
}
setup(**install_options)
if __name__ == "__main__":
main()
python-ptrace-0.9.3/strace.py 0000775 0001750 0001750 00000023761 13047323324 016454 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
from __future__ import print_function
from ptrace import PtraceError
from ptrace.debugger import (PtraceDebugger, Application,
ProcessExit, ProcessSignal, NewProcessEvent, ProcessExecution)
from ptrace.syscall import (SYSCALL_NAMES, SYSCALL_PROTOTYPES,
FILENAME_ARGUMENTS, SOCKET_SYSCALL_NAMES)
from ptrace.func_call import FunctionCallOptions
from sys import stderr, exit
from optparse import OptionParser
from logging import getLogger, error
from ptrace.error import PTRACE_ERRORS, writeError
from ptrace.ctypes_tools import formatAddress
import re
class SyscallTracer(Application):
def __init__(self):
Application.__init__(self)
# Parse self.options
self.parseOptions()
# Setup output (log)
self.setupLog()
def setupLog(self):
if self.options.output:
fd = open(self.options.output, 'w')
self._output = fd
else:
fd = stderr
self._output = None
self._setupLog(fd)
def parseOptions(self):
parser = OptionParser(
usage="%prog [options] -- program [arg1 arg2 ...]")
self.createCommonOptions(parser)
parser.add_option("--enter", help="Show system call enter and exit",
action="store_true", default=False)
parser.add_option("--profiler", help="Use profiler",
action="store_true", default=False)
parser.add_option("--type", help="Display arguments type and result type (default: no)",
action="store_true", default=False)
parser.add_option("--name", help="Display argument name (default: no)",
action="store_true", default=False)
parser.add_option("--string-length", "-s", help="String max length (default: 300)",
type="int", default=300)
parser.add_option("--array-count", help="Maximum number of array items (default: 20)",
type="int", default=20)
parser.add_option("--raw-socketcall", help="Raw socketcall form",
action="store_true", default=False)
parser.add_option("--output", "-o", help="Write output to specified log file",
type="str")
parser.add_option("--ignore-regex", help="Regex used to filter syscall names (e.g. --ignore='^(gettimeofday|futex|f?stat)')",
type="str")
parser.add_option("--address", help="Display structure address",
action="store_true", default=False)
parser.add_option("--syscalls", '-e', help="Comma separated list of shown system calls (other will be skipped)",
type="str", default=None)
parser.add_option("--socket", help="Show only socket functions",
action="store_true", default=False)
parser.add_option("--filename", help="Show only syscall using filename",
action="store_true", default=False)
parser.add_option("--show-pid",
help="Prefix line with process identifier",
action="store_true", default=False)
parser.add_option("--list-syscalls",
help="Display system calls and exit",
action="store_true", default=False)
parser.add_option("-i", "--show-ip",
help="print instruction pointer at time of syscall",
action="store_true", default=False)
self.createLogOptions(parser)
self.options, self.program = parser.parse_args()
if self.options.list_syscalls:
syscalls = list(SYSCALL_NAMES.items())
syscalls.sort(key=lambda data: data[0])
for num, name in syscalls:
print("% 3s: %s" % (num, name))
exit(0)
if self.options.pid is None and not self.program:
parser.print_help()
exit(1)
# Create "only" filter
only = set()
if self.options.syscalls:
# split by "," and remove spaces
for item in self.options.syscalls.split(","):
item = item.strip()
if not item or item in only:
continue
ok = True
valid_names = list(SYSCALL_NAMES.values())
for name in only:
if name not in valid_names:
print("ERROR: unknown syscall %r" % name, file=stderr)
ok = False
if not ok:
print(file=stderr)
print(
"Use --list-syscalls options to get system calls list", file=stderr)
exit(1)
# remove duplicates
only.add(item)
if self.options.filename:
for syscall, format in SYSCALL_PROTOTYPES.items():
restype, arguments = format
if any(argname in FILENAME_ARGUMENTS for argtype, argname in arguments):
only.add(syscall)
if self.options.socket:
only |= SOCKET_SYSCALL_NAMES
self.only = only
if self.options.ignore_regex:
try:
self.ignore_regex = re.compile(self.options.ignore_regex)
except Exception as err:
print("Invalid regular expression! %s" % err)
print("(regex: %r)" % self.options.ignore_regex)
exit(1)
else:
self.ignore_regex = None
if self.options.fork:
self.options.show_pid = True
self.processOptions()
def ignoreSyscall(self, syscall):
name = syscall.name
if self.only and (name not in self.only):
return True
if self.ignore_regex and self.ignore_regex.match(name):
return True
return False
def displaySyscall(self, syscall):
text = syscall.format()
if syscall.result is not None:
text = "%-40s = %s" % (text, syscall.result_text)
prefix = []
if self.options.show_pid:
prefix.append("[%s]" % syscall.process.pid)
if self.options.show_ip:
prefix.append("[%s]" % formatAddress(syscall.instr_pointer))
if prefix:
text = ''.join(prefix) + ' ' + text
error(text)
def syscallTrace(self, process):
# First query to break at next syscall
self.prepareProcess(process)
while True:
# No more process? Exit
if not self.debugger:
break
# Wait until next syscall enter
try:
event = self.debugger.waitSyscall()
except ProcessExit as event:
self.processExited(event)
continue
except ProcessSignal as event:
event.display()
event.process.syscall(event.signum)
continue
except NewProcessEvent as event:
self.newProcess(event)
continue
except ProcessExecution as event:
self.processExecution(event)
continue
# Process syscall enter or exit
self.syscall(event.process)
def syscall(self, process):
state = process.syscall_state
syscall = state.event(self.syscall_options)
if syscall and (syscall.result is not None or self.options.enter):
self.displaySyscall(syscall)
# Break at next syscall
process.syscall()
def processExited(self, event):
# Display syscall which has not exited
state = event.process.syscall_state
if (state.next_event == "exit") \
and (not self.options.enter) \
and state.syscall:
self.displaySyscall(state.syscall)
# Display exit message
error("*** %s ***" % event)
def prepareProcess(self, process):
process.syscall()
process.syscall_state.ignore_callback = self.ignoreSyscall
def newProcess(self, event):
process = event.process
error("*** New process %s ***" % process.pid)
self.prepareProcess(process)
process.parent.syscall()
def processExecution(self, event):
process = event.process
error("*** Process %s execution ***" % process.pid)
process.syscall()
def runDebugger(self):
# Create debugger and traced process
self.setupDebugger()
process = self.createProcess()
if not process:
return
self.syscall_options = FunctionCallOptions(
write_types=self.options.type,
write_argname=self.options.name,
string_max_length=self.options.string_length,
replace_socketcall=not self.options.raw_socketcall,
write_address=self.options.address,
max_array_count=self.options.array_count,
)
self.syscall_options.instr_pointer = self.options.show_ip
self.syscallTrace(process)
def main(self):
if self.options.profiler:
from ptrace.profiler import runProfiler
runProfiler(getLogger(), self._main)
else:
self._main()
if self._output is not None:
self._output.close()
def _main(self):
self.debugger = PtraceDebugger()
try:
self.runDebugger()
except ProcessExit as event:
self.processExited(event)
except PtraceError as err:
error("ptrace() error: %s" % err)
except KeyboardInterrupt:
error("Interrupted.")
except PTRACE_ERRORS as err:
writeError(getLogger(), err, "Debugger error")
self.debugger.quit()
def createChild(self, program):
pid = Application.createChild(self, program)
error("execve(%s, %s, [/* 40 vars */]) = %s" % (
program[0], program, pid))
return pid
if __name__ == "__main__":
SyscallTracer().main()
python-ptrace-0.9.3/doc/ 0000775 0001750 0001750 00000000000 13160156527 015357 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/doc/changelog.rst 0000664 0001750 0001750 00000016773 13160156270 020051 0 ustar haypo haypo 0000000 0000000 .. _changelog:
Changelog
=========
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: Rewrite waitProcessEvent() and waitSignals() methods of
PtraceProcess to not call waitpid() with pid=-1. There is a race condition
with waitpid(-1) and fork, the status of the child process may be returned
before the debugger is noticed of the creation of the new child process.
* Issue #10: Fix PtraceProcess.readBytes() for processes not created by the
debugger (ex: fork) if the kernel blocks access to private mappings of
/proc/pid/mem. Fallback to PTRACE_PEEKTEXT which is slower but a debugger
tracing the process is always allowed to use it.
python-ptrace 0.7 (2013-03-05)
------------------------------
* Experimental support of Python 3.3 in the same code base
* Drop support of Python 2.5
* Remove the ptrace.compatibility module
* Fix 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)
--------------------------------
* Fix os_tools.RUNNING_LINUX for Python 2.x compiled on Linux kernel 3.x
* Support FreeBSD on x86_64
* Add missing prototype of the unlinkat() system call. Patch written by
Matthew Fernandez.
python-ptrace 0.6.5 (2013-06-06)
--------------------------------
* syscall: fix parsing socketcall on Linux x86
* syscall: fix prototype of socket()
python-ptrace 0.6.4 (2012-02-26)
--------------------------------
* Convert all classes to new-style classes, patch written by teythoon
* Fix compilation on Apple, patch written by Anthony Gelibert
* Support GNU/kFreeBSD, patch written by Jakub Wilk
* Support sockaddr_in6 (IPv6 address)
python-ptrace 0.6.3 (2011-02-16)
--------------------------------
* Support distrom3
* Support Python 3
* Rename strace.py option --socketcall to --socket, and fix this option for
FreeBSD and Linux/64 bits
* Add MANIFEST.in: include all files in source distribution (tests, cptrace
module, ...)
python-ptrace 0.6.2 (2009-11-09)
--------------------------------
* Fix 64 bits sub registers (set mask for eax, ebx, ecx, edx)
python-ptrace 0.6.1 (2009-11-07)
--------------------------------
* Create follow, showfollow, resetfollow, xray commands in gdb.py. Patch
written by Dimitris Glynos
* Project website moved to http://bitbucket.org/haypo/python-ptrace/
* Replace types (u)intXX_t by c_(u)intXX
* Create MemoryMapping.search() method and MemoryMapping now keeps a weak
reference to the process
python-ptrace 0.6 (2009-02-13)
------------------------------
User visible changes:
* python-ptrace now depends on Python 2.5
* Invalid memory access: add fault address in the name
* Update Python 3.0 conversion patch
* Create -i (--show-ip) option to strace.py: show instruction pointer
* Add 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)
* Remove PROC_DIRNAME and procFilename() from ptrace.linux_proc
Bugfixes:
* Fix locateProgram() for relative path
* Fix interpretation of memory fault on MOSVW instruction (source is ESI and
destination is EDI, and not the inverse!)
python-ptrace 0.5 (2008-09-13)
------------------------------
Visible changes:
* Write an example (the most simple debugger) and begin to document the code
* gdb.py: create "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:
- Rename PtraceDebugger.traceSysgood() to PtraceDebugger.enableSysgood()
- Rename PtraceDebugger.trace_sysgood to PtraceDebugger.use_sysgood
- Remove PtraceProcess.readCode()
* Create 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: Fix typo in gdb.py (commands => command_str), it wasn't possible to
write more than one command...
* BUGFIX: Fix typo in SignalInfo class (remove "self."). When a process
received a signal SIGCHLD (because of a fork), the debugger exited because
of this bug.
* BUGFIX: Debugger._wait() return 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/
* Create cptrace: optional Python binding of ptrace written in C (faster
than ptrace, the Python binding written in Python with ctypes)
* Add name attribute to SignalInfo classes
* Fixes to help Python 3.0 compatibility: don't use sys.exc_clear()
(was useless) in writeBacktrace()
* ProcessState: create utime, stime, starttime attributes
python-ptrace 0.4.0 (2008-08-19)
--------------------------------
Visible changes:
* Rename the project to "python-ptrace" (old name was "Ptrace)
* strace.py: create --ignore-regex option
* PtraceSignal: support SIGBUS, display the related registers and
the instruction
* Support execve() syscall tracing
Developer changes:
* New API is incompatible with 0.3.2
* 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
* Remove iterProc() function, replaced by openProc() with explicit
call to .close() to make sure that files are closed
* Create searchProcessesByName()
* Replace CPU_PPC constant by CPU_POWERPC and create CPU_PPC32 and CPU_PPC64
* Create 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
python-ptrace-0.9.3/doc/index.rst 0000664 0001750 0001750 00000006767 13047321200 017222 0 ustar haypo haypo 0000000 0000000 =============
python-ptrace
=============
python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to
trace processes) written in Python.
* `python-ptrace documentation
`_
* `python-ptrace at GitHub
`_
* `python-ptrace at the Python Cheeseshop (PyPI)
`_
python-ptrace is an opensource project written in Python under GNU GPLv2
license.
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 `_ disassembler
* Dump registers, memory mappings, stack, etc.
* :ref:`Syscall tracer and parser ` (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
=================
.. toctree::
:maxdepth: 2
install
usage
syscall
gdb
process_events
ptrace_signal
cptrace
authors
changelog
todo
Links
=====
Project using python-ptrace
---------------------------
* `Fusil the fuzzer `_
python-ptrace announces
-----------------------
* `fuzzing mailing list `_
* `reverse-engineering.net `_
ptrace usage
------------
* Sandboxing: `Plash `_
Similar projects
----------------
* `vtrace `_: Python library (Windows and Linux) supporting threads
* `subterfuge `_ by Mike Coleman: Python library (Linux): contains Python binding of ptrace written in C for Python 2.1/2.2. It doesn't work with Python 2.5 (old project, not maintained since 2002)
* `strace `_ program (Linux, BSD)
* ltrace program (Linux)
* truss program (Solaris and BSD)
* `pytstop `_ by Philippe Biondi: debugger similar to gdb but in very alpha stage (e.g. no disassembler), using ptrace Python binding written in C (from subterfuge)
* `strace.py `_ by Philippe Biondi
* `Fenris `_: suite of tools suitable for code analysis, debugging, protocol analysis, reverse engineering, forensics, diagnostics, security audits, vulnerability research
* `PyDBG `_: Windows debugger written in pure Python
Interesting articles
-----------------------
* (fr) `Surveiller les connexions avec auditd `_ (2007)
* `Playing with ptrace() for fun and profit `_ (2006)
* `PTRACE_SETOPTIONS tests `_ (2005)
* `Process Tracing Using Ptrace `_ (2002)
python-ptrace-0.9.3/doc/gdb.rst 0000664 0001750 0001750 00000006054 13047321200 016634 0 ustar haypo haypo 0000000 0000000 ++++++
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
========
* 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 `. 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
(active)
(gdb) proc
Process ID: 24187 (parent: 24182)
Process state: T (traced)
Process command line: [['tests/fork_execve']
(...)
(gdb)|switch; proc
Switch to
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<
Quit gdb.
python-ptrace-0.9.3/doc/cptrace.rst 0000664 0001750 0001750 00000000564 13047321200 017521 0 ustar haypo haypo 0000000 0000000 +++++++++++++++++++++
cptrace Python module
+++++++++++++++++++++
Python binding for ptrace written in C.
Example
=======
Dummy example: ::
>>> import cptrace
>>> cptrace.ptrace(1, 1)
Traceback (most recent call last):
File "", line 1, in
ValueError: ptrace(request=1, pid=1, 0x(nil), 0x(nil)) error #1: Operation not permitted
python-ptrace-0.9.3/doc/syscall.rst 0000664 0001750 0001750 00000005440 13047321200 017550 0 ustar haypo haypo 0000000 0000000 .. _syscall:
+++++++++++++++++++++++++++++
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, , 28) = 0
open('/usr/lib/i686/cmov/libcrypto.so.0.9.8', 0, 0 ) = 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 ) = 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
--------
* 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 /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
-------
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, , 110) = -2 (No such file or directory)
socket(AF_FILE, SOCK_STREAM, 0) = 3
connect(3, , 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, , 16) = -111 (Connection refused)
(...)
python-ptrace-0.9.3/doc/ptrace_signal.rst 0000664 0001750 0001750 00000005633 13047321200 020715 0 ustar haypo haypo 0000000 0000000 .. _signal:
+++++++++++++++++++++++++++++
python-ptrace signal handling
+++++++++++++++++++++++++++++
Introduction
============
PtraceSignal tries to display useful information when a signal is received.
Depending on the signal number, it shows different information.
It uses the current instruction decoded as assembler code to understand why
the signal is raised.
Only Intel x86 (i386, maybe x86_64) is supported now.
When a process receives a signal, python-ptrace tries to explain why the signal was emitted.
General information (not shown for all signals, e.g. not for SIGABRT):
* CPU instruction causing the crash
* CPU registers related to the crash
* 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:
* Address of the segmentation fault
* (if possible) Size of the invalid memory read/write
* CPU instruction causing the crash
* CPU registers related to the crash
* 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 =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
========
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
===========
See:
* ``ptrace/debugger/ptrace_signal.py``
* ``ptrace/debugger/signal_reason.py``
python-ptrace-0.9.3/doc/todo.rst 0000664 0001750 0001750 00000003145 13047321200 017043 0 ustar haypo haypo 0000000 0000000 TODO
====
Main tasks
----------
* Fix strace.py --socketcall: SyscallState.enter() calls ignore_callback
before socketcall are proceed
* Support other backends:
- GDB MI: http://code.google.com/p/pygdb/
- ktrace: (FreeBSD and Darwin): would help Darwin support
- utrace (new Linux debugger): http://sourceware.org/systemtap/wiki/utrace
- vtrace?
- PyDBG: works on Windows
* Backtrace symbols:
- GNU BFD?
- elfsh?
- addr2line program?
- See dl_iterate_phdr() function of libdl
* Support other disassemblers (than distorm), and so both Intel syntax (Intel and AT&T)
- BFD
- http://www.ragestorm.net/distorm/
- libasm (ERESI)
- libdisasm (bastard)
- http://www.woodmann.com/collaborative/tools/index.php/Category:X86_Disassembler_Libraries
* Support threads: other backends (than python-ptrace) already support threads
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)
* Remove gdb.py "except PtraceError, err: if err.errno == ESRCH" hack,
process death detection should be done by PtraceProcess or PtraceDebugger
* Use Intel hardware breakpoints: set vtrace source code
* Support Darwin:
- ktrace? need to recompile Darwin kernel with KTRACE option
- get registers: http://unixjunkie.blogspot.com/2006/01/darwin-ptrace-and-registers.html
- PT_DENY_ATTACH: http://steike.com/code/debugging-itunes-with-gdb/
- PT_DENY_ATTACH: http://landonf.bikemonkey.org/code/macosx/ptrace_deny_attach.20041010201303.11809.mojo.html
python-ptrace-0.9.3/doc/usage.rst 0000664 0001750 0001750 00000004634 13047321200 017206 0 ustar haypo haypo 0000000 0000000 +++++++++++++++++++
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.
python-ptrace-0.9.3/doc/Makefile 0000664 0001750 0001750 00000012727 13047321200 017012 0 ustar haypo haypo 0000000 0000000 # Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-ptrace.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-ptrace.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/python-ptrace"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-ptrace"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
python-ptrace-0.9.3/doc/make.bat 0000664 0001750 0001750 00000011766 13047321200 016761 0 ustar haypo haypo 0000000 0000000 @ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^` where ^ is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python-ptrace.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python-ptrace.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end
python-ptrace-0.9.3/doc/authors.rst 0000664 0001750 0001750 00000001222 13047321200 017555 0 ustar haypo haypo 0000000 0000000 +++++++
Authors
+++++++
Contributors
============
* Anthony Gelibert - fix cptrace on Apple
* Dimitris Glynos - follow gdb.py commands
* Jakub Wilk - fix for GNU/kFreeBSD
* Mark Seaborn - Create -i option for strace
* Mickaël Guérin aka KAeL - OpenBSD port
* teythoon - convert all classes to new-style classes
* T. Bursztyka aka Tuna - x86_64 port
* Victor Stinner - python-ptrace author and maintainer
Thanks
======
* procps authors (top and uptime programs)
python-ptrace-0.9.3/doc/install.rst 0000664 0001750 0001750 00000004275 13047321200 017551 0 ustar haypo haypo 0000000 0000000 +++++++++++++++++++++
Install python-ptrace
+++++++++++++++++++++
Linux packages
==============
* Debian: `python-ptrace Debian package `_.
* Mandriva: `python-ptrace Mandriva package `_
* OpenEmbedded: `python-ptrace recipe `_
* Arch Linux: `python-ptrace Arch Linux package `_
* Gentoo: `dev-python/python-ptrace `_
See also `python-ptrace on Python Package Index (PyPI) `_
Install from source
===================
Download tarball
----------------
Get the latest tarball at the `Python Package Index (PyPI)
`_.
Download development version
----------------------------
Download the development version using Git::
git clone https://github.com/haypo/python-ptrace.git
`Browse python-ptrace source code
`_.
python-ptrace dependencies
--------------------------
* Python 2.6+/3.3+:
http://python.org/
* distorm disassembler (optional)
http://www.ragestorm.net/distorm/
Installation
------------
Type as root::
python setup.py install
Or using sudo program::
sudo python 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::
python setup_cptrace.py install
Run tests
=========
Run tests with tox
------------------
The `tox project `_ can be used to build a
virtual environment run tests against different Python versions (Python 2 and
Python 3).
To run all tests on Python 2 and Python 3, just type::
tox
To only run tests on Python 2.7, type::
tox -e py2
Available environments:
* ``py2``: Python 2
* ``py3``: Python 3
Run tests manually
------------------
Type::
python runtests.py
python test_doc.py
It's also possible to run a specific test::
PYTHONPATH=$PWD python tests/test_strace.py
python-ptrace-0.9.3/doc/conf.py 0000664 0001750 0001750 00000017070 13050122256 016651 0 ustar haypo haypo 0000000 0000000 # -*- coding: utf-8 -*-
#
# python-ptrace documentation build configuration file, created by
# sphinx-quickstart on Mon Mar 31 10:08:56 2014.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'python-ptrace'
copyright = u'2014, Victor Stinner'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = release = '0.9.3'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'python-ptracedoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'python-ptrace.tex', u'python-ptrace Documentation',
u'Victor Stinner', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'python-ptrace', u'python-ptrace Documentation',
[u'Victor Stinner'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'python-ptrace', u'python-ptrace Documentation',
u'Victor Stinner', 'python-ptrace', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
python-ptrace-0.9.3/doc/process_events.rst 0000664 0001750 0001750 00000003623 13047321200 021141 0 ustar haypo haypo 0000000 0000000 ++++++++++++++++++++++++++++
python-ptrace process events
++++++++++++++++++++++++++++
Process events
==============
All process events are based on ProcessEvent class.
* ProcessExit: process exited with an exitcode, killed by a signal
or exited abnormally
* ProcessSignal: process received a signal
* NewProcessEvent: new process created, e.g. after a fork() syscall
Attributes:
* All events have a "process" attribute
* ProcessExit has "exitcode" and "signum" attributes (both can be None)
* ProcessSignal has "signum" and "name" attributes
For NewProcessEvent, use process.parent attribute to get the parent process.
Note: ProcessSignal has a display() method to display its content. Use it
just after receiving the message because it reads process memory to analyze
the reasons why the signal was sent.
Wait for any process event
==========================
The most generic function is waitProcessEvent(): it waits for any process
event (exit, signal or new process): ::
event = debugger.waitProcessEvent()
To wait one or more signals, use waitSignals() methods. With no argument,
it waits for any signal. Events different than signal are raised as
Python exception. Examples: ::
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
==================================
To wait any event from a process, use waitEvent() method: ::
event = process.waitEvent()
To wait one or more signals, use waitSignals() method. With no argument,
it waits for any signal. Other process events are raised as Python
exception. Examples: ::
signal = process.waitSignals()
signal = process.waitSignals(SIGTRAP)
signal = process.waitSignals(SIGINT, SIGTERM)
Note: As debugger.waitSignals(), signal is a ProcessSignal object.
python-ptrace-0.9.3/PKG-INFO 0000664 0001750 0001750 00000003270 13160156527 015711 0 ustar haypo haypo 0000000 0000000 Metadata-Version: 1.1
Name: python-ptrace
Version: 0.9.3
Summary: python binding of ptrace
Home-page: http://python-ptrace.readthedocs.io/
Author: Victor Stinner
Author-email: UNKNOWN
License: GNU GPL v2
Download-URL: http://python-ptrace.readthedocs.io/
Description-Content-Type: UNKNOWN
Description: =============
python-ptrace
=============
.. image:: https://img.shields.io/pypi/v/python-ptrace.svg
:alt: Latest release on the Python Cheeseshop (PyPI)
:target: https://pypi.python.org/pypi/python-ptrace
.. image:: https://travis-ci.org/haypo/python-ptrace.svg?branch=master
:alt: Build status of python-ptrace on Travis CI
:target: https://travis-ci.org/haypo/python-ptrace
python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to
trace processes) written in Python.
* `python-ptrace documentation
`_
* `python-ptrace at GitHub
`_
* `python-ptrace at the Python Cheeseshop (PyPI)
`_
python-ptrace is an opensource project written in Python under GNU GPLv2
license.
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
Classifier: Operating System :: OS Independent
Classifier: Natural Language :: English
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
python-ptrace-0.9.3/pyflakes.sh 0000775 0001750 0001750 00000000147 13047321200 016753 0 ustar haypo haypo 0000000 0000000 pyflakes $(find -name "*.py")|grep -v "redefinition of unused"|grep -v "__init__.*imported but unused"
python-ptrace-0.9.3/cptrace/ 0000775 0001750 0001750 00000000000 13160156527 016233 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/cptrace/version.py 0000664 0001750 0001750 00000000156 13047321200 020256 0 ustar haypo haypo 0000000 0000000 PACKAGE = "cptrace"
VERSION = "0.6.1"
WEBSITE = "http://python-ptrace.readthedocs.io/"
LICENSE = "GNU GPL v2"
python-ptrace-0.9.3/cptrace/cptrace.c 0000664 0001750 0001750 00000005012 13047321200 020000 0 ustar haypo haypo 0000000 0000000 #include
#include
#if __APPLE__
#include
#endif
#include
#define UNUSED(arg) arg __attribute__((unused))
char python_ptrace_DOCSTR[] =
"ptrace(command: int, pid: int, arg1=0, arg2=0, check_errno=False): call ptrace syscall.\r\n"
"Raise a ValueError on error.\r\n"
"Returns an unsigned integer.\r\n";
static bool cpython_cptrace(
unsigned int request,
pid_t pid,
void *arg1,
void *arg2,
bool check_errno,
unsigned long *result)
{
unsigned long ret;
errno = 0;
ret = ptrace(request, pid, arg1, arg2);
if ((long)ret == -1) {
/**
* peek operations may returns -1 with errno=0: it's not an error.
* For other operations, -1 is always an error
*/
if (!check_errno || errno) {
PyErr_Format(
PyExc_ValueError,
"ptrace(request=%u, pid=%i, %p, %p) "
"error #%i: %s",
request, pid, arg1, arg2,
errno, strerror(errno));
return false;
}
}
if (result)
*result = ret;
return true;
}
static PyObject* cpython_ptrace(PyObject* UNUSED(self), PyObject *args, PyObject *keywds)
{
unsigned long result;
unsigned int request;
pid_t pid;
unsigned long arg1 = 0;
unsigned long arg2 = 0;
bool check_errno = false;
PyObject* check_errno_p = NULL;
static char *kwlist[] = {"request", "pid", "arg1", "arg2", "check_errno", NULL};
if (!PyArg_ParseTupleAndKeywords(args, keywds,
"Ii|LLO", kwlist,
&request, &pid, &arg1, &arg2, &check_errno_p
))
{
return NULL;
}
if (check_errno_p) {
check_errno = PyObject_IsTrue(check_errno_p);
}
if (cpython_cptrace(request, pid, (void*)arg1, (void*)arg2, check_errno, &result))
return PyLong_FromUnsignedLong(result);
else
return NULL;
}
static PyMethodDef module_methods[] = {
{"ptrace", (PyCFunction)cpython_ptrace, METH_VARARGS | METH_KEYWORDS, python_ptrace_DOCSTR},
{NULL, NULL, 0, NULL}
};
PyDoc_STRVAR(module_doc,
"ptrace module written in C");
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef module_def = {
PyModuleDef_HEAD_INIT,
"cptrace",
module_doc,
0,
module_methods,
NULL
};
#endif
PyMODINIT_FUNC
#if PY_MAJOR_VERSION >= 3
PyInit_cptrace(void)
#else
initcptrace(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
return PyModule_Create(&module_def);
#else
(void)Py_InitModule3("cptrace", module_methods, module_doc);
#endif
}
python-ptrace-0.9.3/cptrace/Makefile 0000664 0001750 0001750 00000000333 13047321200 017654 0 ustar haypo haypo 0000000 0000000 CC=gcc
CFLAGS=-fPIC -shared -Wall -Wextra -Wextra $(shell python-config --cflags)
LIBS=$(shell python-config --libs)
LIBRARY=cptrace.so
$(LIBRARY): cptrace.c
$(CC) -o $@ $< $(CFLAGS) $(LIBS)
clean:
rm -f $(LIBRARY)
python-ptrace-0.9.3/setup.py 0000775 0001750 0001750 00000004211 13160156514 016321 0 ustar haypo haypo 0000000 0000000 #!/usr/bin/env python
# Prepare a release:
#
# - git pull --rebase # check that there is no incoming changesets
# - check version in ptrace/version.py and doc/conf.py
# - set release date in doc/changelog.rst
# - check that "python setup.py sdist" contains all files tracked by
# the SCM (Git): update MANIFEST.in if needed
# - git commit -a -m "prepare release VERSION"
# - run tests, type: tox
# - git push
# - check Travis status:
# https://travis-ci.org/haypo/python-ptrace
#
# Release a new version:
#
# - git tag python-ptrace-VERSION
# - git push --tags
# - git clean -fdx # WARNING: Remove all untracked files!
# - python3 setup.py sdist bdist_wheel
# - twine upload dist/*
#
# After the release:
#
# - increment version in ptrace/version.py and doc/conf.py
# - git commit -a -m "post-release"
# - git push
from __future__ import with_statement
from imp import load_source
from os import path
try:
# setuptools supports bdist_wheel
from setuptools import setup
except ImportError:
from distutils.core import setup
MODULES = ["ptrace", "ptrace.binding", "ptrace.syscall", "ptrace.debugger"]
SCRIPTS = ("strace.py", "gdb.py")
CLASSIFIERS = [
'Intended Audience :: Developers',
'Development Status :: 4 - Beta',
'Environment :: Console',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Operating System :: OS Independent',
'Natural Language :: English',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
]
with open('README.rst') as fp:
LONG_DESCRIPTION = fp.read()
ptrace = load_source("version", path.join("ptrace", "version.py"))
PACKAGES = {}
for name in MODULES:
PACKAGES[name] = name.replace(".", "/")
install_options = {
"name": ptrace.PACKAGE,
"version": ptrace.VERSION,
"url": ptrace.WEBSITE,
"download_url": ptrace.WEBSITE,
"author": "Victor Stinner",
"description": "python binding of ptrace",
"long_description": LONG_DESCRIPTION,
"classifiers": CLASSIFIERS,
"license": ptrace.LICENSE,
"packages": list(PACKAGES.keys()),
"package_dir": PACKAGES,
"scripts": SCRIPTS,
}
setup(**install_options)
python-ptrace-0.9.3/python_ptrace.egg-info/ 0000775 0001750 0001750 00000000000 13160156527 021163 5 ustar haypo haypo 0000000 0000000 python-ptrace-0.9.3/python_ptrace.egg-info/top_level.txt 0000664 0001750 0001750 00000000007 13160156527 023712 0 ustar haypo haypo 0000000 0000000 ptrace
python-ptrace-0.9.3/python_ptrace.egg-info/SOURCES.txt 0000664 0001750 0001750 00000004544 13160156527 023056 0 ustar haypo haypo 0000000 0000000 COPYING
MANIFEST.in
README.rst
gdb.py
pyflakes.sh
runtests.py
setup.py
setup_cptrace.py
strace.py
test_doc.py
tox.ini
cptrace/Makefile
cptrace/cptrace.c
cptrace/version.py
doc/Makefile
doc/authors.rst
doc/changelog.rst
doc/conf.py
doc/cptrace.rst
doc/gdb.rst
doc/index.rst
doc/install.rst
doc/make.bat
doc/process_events.rst
doc/ptrace_signal.rst
doc/syscall.rst
doc/todo.rst
doc/usage.rst
examples/itrace.py
examples/simple_dbg.py
ptrace/__init__.py
ptrace/cpu_info.py
ptrace/ctypes_libc.py
ptrace/ctypes_tools.py
ptrace/disasm.py
ptrace/error.py
ptrace/func_arg.py
ptrace/func_call.py
ptrace/linux_proc.py
ptrace/logging_tools.py
ptrace/mockup.py
ptrace/os_tools.py
ptrace/process_tools.py
ptrace/profiler.py
ptrace/pydistorm.py
ptrace/signames.py
ptrace/six.py
ptrace/terminal.py
ptrace/tools.py
ptrace/version.py
ptrace/binding/__init__.py
ptrace/binding/cpu.py
ptrace/binding/freebsd_struct.py
ptrace/binding/func.py
ptrace/binding/linux_struct.py
ptrace/binding/openbsd_struct.py
ptrace/debugger/__init__.py
ptrace/debugger/application.py
ptrace/debugger/backtrace.py
ptrace/debugger/breakpoint.py
ptrace/debugger/child.py
ptrace/debugger/debugger.py
ptrace/debugger/memory_mapping.py
ptrace/debugger/parse_expr.py
ptrace/debugger/process.py
ptrace/debugger/process_error.py
ptrace/debugger/process_event.py
ptrace/debugger/ptrace_signal.py
ptrace/debugger/signal_reason.py
ptrace/debugger/syscall_state.py
ptrace/syscall/__init__.py
ptrace/syscall/freebsd_constants.py
ptrace/syscall/freebsd_syscall.py
ptrace/syscall/linux_constants.py
ptrace/syscall/linux_struct.py
ptrace/syscall/linux_syscall32.py
ptrace/syscall/linux_syscall64.py
ptrace/syscall/names.py
ptrace/syscall/posix_arg.py
ptrace/syscall/posix_constants.py
ptrace/syscall/prototypes.py
ptrace/syscall/ptrace_syscall.py
ptrace/syscall/socketcall.py
ptrace/syscall/socketcall_constants.py
ptrace/syscall/socketcall_struct.py
ptrace/syscall/syscall_argument.py
python_ptrace.egg-info/PKG-INFO
python_ptrace.egg-info/SOURCES.txt
python_ptrace.egg-info/dependency_links.txt
python_ptrace.egg-info/top_level.txt
tests/test_gdb.py
tests/test_strace.py
tests/crash/BSDmakefile
tests/crash/Makefile
tests/crash/abort.c
tests/crash/call_null.c
tests/crash/div_zero.c
tests/crash/execve.c
tests/crash/fork.c
tests/crash/invalid_read.c
tests/crash/invalid_write.c
tests/crash/pthread.c
tests/crash/socket_ipv4_tcp.c
tests/crash/stack_overflow.c python-ptrace-0.9.3/python_ptrace.egg-info/dependency_links.txt 0000664 0001750 0001750 00000000001 13160156527 025231 0 ustar haypo haypo 0000000 0000000
python-ptrace-0.9.3/python_ptrace.egg-info/PKG-INFO 0000664 0001750 0001750 00000003270 13160156527 022262 0 ustar haypo haypo 0000000 0000000 Metadata-Version: 1.1
Name: python-ptrace
Version: 0.9.3
Summary: python binding of ptrace
Home-page: http://python-ptrace.readthedocs.io/
Author: Victor Stinner
Author-email: UNKNOWN
License: GNU GPL v2
Download-URL: http://python-ptrace.readthedocs.io/
Description-Content-Type: UNKNOWN
Description: =============
python-ptrace
=============
.. image:: https://img.shields.io/pypi/v/python-ptrace.svg
:alt: Latest release on the Python Cheeseshop (PyPI)
:target: https://pypi.python.org/pypi/python-ptrace
.. image:: https://travis-ci.org/haypo/python-ptrace.svg?branch=master
:alt: Build status of python-ptrace on Travis CI
:target: https://travis-ci.org/haypo/python-ptrace
python-ptrace is a debugger using ptrace (Linux, BSD and Darwin system call to
trace processes) written in Python.
* `python-ptrace documentation
`_
* `python-ptrace at GitHub
`_
* `python-ptrace at the Python Cheeseshop (PyPI)
`_
python-ptrace is an opensource project written in Python under GNU GPLv2
license.
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
Classifier: Operating System :: OS Independent
Classifier: Natural Language :: English
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3