File: parse_expr.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 (75 lines) | stat: -rw-r--r-- 2,047 bytes parent folder | download | duplicates (3)
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
import re

# Match a register name: $eax, $gp0, $orig_eax
REGISTER_REGEX = re.compile(r"([a-z]+[a-z0-9_]+)")

# Hexadacimel number (eg. 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", "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