File: signal_reason.py

package info (click to toggle)
python-ptrace 0.7-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch
  • size: 680 kB
  • ctags: 1,002
  • sloc: python: 6,659; ansic: 263; makefile: 13; sh: 1
file content (165 lines) | stat: -rw-r--r-- 5,648 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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 as err:
            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 InvalidMemoryAcces(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(InvalidMemoryAcces):
    NAME = "invalid_read"
    PREFIX = "Invalid read"
    PREFIX_ADDR = "Invalid read from %s"

class InvalidWrite(InvalidMemoryAcces):
    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)