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>': 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={'<instr pointer>': 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)
|