Edit File: signal_reason.py
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)