Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 6 additions & 20 deletions leep/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,16 @@ def parseTransaction(xact):
Example Implied Transaction
-------------------------------------------
regname Read from named register (str) 'regname'
regaddr Read from explicit address (int) 'regaddr'
regname=val Write (int) 'val' to named register (str) 'regname'
regaddr=val Write (int) 'val' to explicit address (int) 'regaddr'
regname=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at the
address of named register (str) 'regname'
regaddr=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
address (int) 'regaddr'
regname+offset Read from address = romx['regname']['base_addr'] + (int) 'offset'
regaddr+offset Read from address = (int) 'regaddr' + (int) 'offset'
regname:size Read (int) 'size' elements starting from address romx['regname']['base_addr']
regaddr:size Read (int) 'size' elements starting from (int) 'regaddr'
regname+offset=val Write (int) 'val' to address romx['regname']['base_addr'] + (int) 'offset'
regname+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
address romx['regname']['base_addr'] + (int) 'offset'
regaddr+offset=val Write (int) 'val' to address (int) 'regaddr' + (int) 'offset'
regaddr+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
address (int) 'regaddr'
regname+offset:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] + \
(int) 'offset'
regaddr+offset:size Read (int) 'size' elements starting from (int) 'regaddr' + (int) 'offset'
I'm not sure what use case the "regaddr+offset" syntax supports, but it does no harm to include it.
NOTE! Deliberately not supporting "regname-offset" (negative offsets) as it's use case is unclear
and a '_' to '-' typo could potentially collide with legitimate transactions.
"""
Expand All @@ -74,13 +63,16 @@ def parseTransaction(xact):
size = None
if _match:
groups = _match.groups()
regstr = groups[0] # Always starts with 'regname' or 'regaddr'
regstr = groups[0] # Always starts with 'regname'
if regstr.isdigit() or regstr.lower().startswith("0x") or regstr.lower().startswith("0b"):
raise ValueError("Absolute numeric addresses are not allowed. Use symbolic register names instead.")
if groups[1] == '=':
wval = _expandWriteVals(groups[2])
elif groups[1] == '+':
offset = _int(groups[2])
elif groups[1] == ':':
size = _int(groups[2])

if groups[3] == '=':
if groups[1] == '=':
raise Exception("Malformed transaction: {}".format(xact))
Expand All @@ -91,15 +83,9 @@ def parseTransaction(xact):
size = _int(groups[4])
else:
raise Exception("Failed to match: {}".format(xact))
try:
reg = _int(regstr)
except ValueError:
reg = regstr
reg = regstr
if size is None:
if wval is None:
size = None
else:
size = 0
size = 0 if wval is not None else None
return (reg, offset, size, wval)


Expand Down
18 changes: 6 additions & 12 deletions leep/raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,12 @@ def log2(n):


def _int(s):
if isinstance(s, str) and (s.isdigit() or s.lower().startswith(('0x', '0b'))):
raise ValueError("Absolute numeric addressing is not allowed. Use symbolic register names instead.")
try:
# Catch actual ints
return int(s)
except ValueError:
pass
if hasattr(s, 'startswith'):
try:
if s.startswith('0x'):
return int(s, 16)
elif s.startswith('0b'):
return int(s, 2)
except ValueError:
pass
return None
return None


class LEEPDevice(DeviceBase):
Expand Down Expand Up @@ -176,9 +168,11 @@ def _decode(self, reg, instance=[]):
"data_width": 32,
"sign": "unsigned",
}
if isinstance(reg, str) and (reg.isdigit() or reg.lower().startswith(('0x', '0b'))):
raise ValueError("Absolute numeric addressing is not allowed. Use symbolic register names instead.")
_reg = _int(reg)
if _reg is not None:
return "0x{:x}".format(_reg), _reg, 1, info
raise ValueError("Absolute numeric addressing is not allowed. Use symbolic register names instead.")
if instance is not None:
reg = self.expand_regname(reg, instance=instance)
info = self.get_reg_info(reg, instance=None)
Expand Down
59 changes: 38 additions & 21 deletions leep/test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,46 +238,48 @@ def test_parseTransaction():
# CLI string: result (reg, offset, read_size, write_vals)
# regname Read from named register (str) 'regname'
"foo": ("foo", 0, None, None),
# regaddr Read from explicit address (int) 'regaddr'
"0x100": (0x100, 0, None, None),
# regname=val Write (int) 'val' to named register (str) 'regname'
"foo=42": ("foo", 0, 0, 42),
"bar=0x42": ("bar", 0, 0, 0x42),
"foo_baz=0b100": ("foo_baz", 0, 0, 0b100),
# regaddr=val Write (int) 'val' to explicit address (int) 'regaddr'
"0x123=100": (0x123, 0, 0, 100),
"123=0xabc": (123, 0, 0, 0xabc),
"0b1010=-10": (0b1010, 0, 0, -10),
# regname=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at the
# address of named register (str) 'regname'
"reg_foo=1,2,3,4,5": ("reg_foo", 0, 0, [1, 2, 3, 4, 5]),
# regaddr=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
# address (int) 'regaddr'
"0x4000=1,-1,0,42,0x10": (0x4000, 0, 0, [1, -1, 0, 42, 0x10]),
# regname+offset Read from address = romx['regname']['base_addr'] + (int) 'offset'
"BINGO+100": ("BINGO", 100, None, None),
# regaddr+offset Read from address = (int) 'regaddr' + (int) 'offset'
"0x100+100": (0x100, 100, None, None),
# regname:size Read (int) 'size' elements starting from address romx['regname']['base_addr']
"_reg_:32": ("_reg_", 0, 32, None),
# regaddr:size Read (int) 'size' elements starting from (int) 'regaddr'
"0:0xff": (0, 0, 0xff, None),
# regname+offset=val Write (int) 'val' to address romx['regname']['base_addr'] + (int) 'offset'
"bandit+0x100=5000": ("bandit", 0x100, 0, 5000),
# regname+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
# address romx['regname']['base_addr'] + (int) 'offset'
"status+0x20=50,40,0x30": ("status", 0x20, 0, [50, 40, 0x30]),
# regaddr+offset=val Write (int) 'val' to address (int) 'regaddr' + (int) 'offset'
"128+0xc0=-1000": (128, 0xc0, 0, -1000),
# regaddr+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
# address (int) 'regaddr'
"0x128+0xc0=1,0,1,0,2": (0x128, 0xc0, 0, [1, 0, 1, 0, 2]),
# regname+offset:size Read (int) 'size' elements starting from address romx['regname']['base_addr'] + \
# (int) 'offset'
"Socks+0x100:100": ("Socks", 0x100, 100, None),
# regaddr+offset:size Read (int) 'size' elements starting from (int) 'regaddr' + (int) 'offset'
"0x4000+15:0b1111": (0x4000, 15, 0b1111, None),
}
bads = [
# regaddr Read from explicit address (int) 'regaddr'
"0x100",
# regaddr=val Write (int) 'val' to explicit address (int) 'regaddr'
"0x123=100",
"123=0xabc",
"0b1010=-10",
# regaddr=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
# address (int) 'regaddr'
"0x4000=1,-1,0,42,0x10",
# regaddr+offset Read from address = (int) 'regaddr' + (int) 'offset'
"0x100+100",
# regaddr:size Read (int) 'size' elements starting from (int) 'regaddr'
"0:0xff",
# regaddr+offset=val Write (int) 'val' to address (int) 'regaddr' + (int) 'offset'
"128+0xc0=-1000",
# regaddr+offset=val0,...,valN Write (int) 'val0' through 'valN' to consecutive addresses beginning at
# address (int) 'regaddr'
"0x128+0xc0=1,0,1,0,2",
# regaddr+offset:size Read (int) 'size' elements starting from (int) 'regaddr' + (int) 'offset'
"0x4000+15:0b1111",
]
errors = 0
for _input, _expected in dd.items():
try:
Expand All @@ -287,6 +289,17 @@ def test_parseTransaction():
if result != _expected:
print("Failed on input: {}.\n Expected: {}\n Result: {}".format(_input, _expected, result))
errors += 1

for _input in bads:
try:
result = parseTransaction(_input)
print(f"Expected an exception for input: { _input } but got {result}")
errors += 1
except ValueError:
pass
except Exception as ex:
print(f"Unexpected exception for input: { _input }: { ex }")
errors += 1
return errors


Expand Down Expand Up @@ -318,4 +331,8 @@ def runServer(args):
parserTest = subparsers.add_parser("test", help="Run regression tests.")
parserTest.set_defaults(handler=doTests)
args = parser.parse_args()
sys.exit(args.handler(args))
try:
args.handler(args)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
19 changes: 12 additions & 7 deletions leep/test/test_raw.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import logging

import unittest
Expand Down Expand Up @@ -195,15 +194,21 @@ def test_raw_int():
from leep.raw import _int
tests = {
"foo": None,
"123": 123,
"0x100": 0x100,
"0b1000": 0b1000,
"123": 123, # should raise error
"0x100": 0x100, # should raise error
"0b1000": 0b1000, # should raise error
"0xreg": None,
"0bentry": None,
}
for key, val in tests.items():
if val != _int(key):
raise Exception("Test failed _int({}) = {} != {}".format(key, _int(key), val))
for key in tests:
try:
result = _int(key)
if result is not None:
print(f"Found passing absolute numeric address: {key} -> {result}")
raise Exception(f"Test failed _int({key}) = {result} (accepted when it shouldn't)")
except ValueError:
print(f"Expected ValueError for input '{key}' detected, as intended")
continue
return True


Expand Down
Loading