Skip to content

Commit 4effb33

Browse files
Merge pull request #2 from trailofbits/refactor
refactor
2 parents c367e4f + 7aad5db commit 4effb33

File tree

10 files changed

+239
-786
lines changed

10 files changed

+239
-786
lines changed

.gitignore

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
env/
12+
build/
13+
develop-eggs/
14+
dist/
15+
downloads/
16+
eggs/
17+
.eggs/
18+
lib/
19+
lib64/
20+
parts/
21+
sdist/
22+
var/
23+
wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
28+
# PyInstaller
29+
# Usually these files are written by a python script from a template
30+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
31+
*.manifest
32+
*.spec
33+
34+
# Installer logs
35+
pip-log.txt
36+
pip-delete-this-directory.txt
37+
38+
# Unit test / coverage reports
39+
htmlcov/
40+
.tox/
41+
.coverage
42+
.coverage.*
43+
.cache
44+
nosetests.xml
45+
coverage.xml
46+
*,cover
47+
.hypothesis/
48+
49+
# Translations
50+
*.mo
51+
*.pot
52+
53+
# Django stuff:
54+
*.log
55+
local_settings.py
56+
57+
# Flask stuff:
58+
instance/
59+
.webassets-cache
60+
61+
# Scrapy stuff:
62+
.scrapy
63+
64+
# Sphinx documentation
65+
docs/_build/
66+
67+
# PyBuilder
68+
target/
69+
70+
# Jupyter Notebook
71+
.ipynb_checkpoints
72+
73+
# pyenv
74+
.python-version
75+
venvpy/
76+
# celery beat schedule file
77+
celerybeat-schedule
78+
79+
# dotenv
80+
.env
81+
82+
# virtualenv
83+
.venv
84+
venv/
85+
ENV/
86+
87+
# Spyder project settings
88+
.spyderproject
89+
90+
# Rope project settings
91+
.ropeproject
92+
93+
# macOS Finder files
94+
.DS_Store
95+
96+
# PyCharm files
97+
.idea/

pyevmasm/__init__.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
1-
2-
# try importing python 3 module first
3-
try:
4-
from pyevmasm.evmasm3 import *
5-
except:
6-
from evmasm2 import *
1+
from .evmasm import EVMAsm

pyevmasm/evmasm2.py renamed to pyevmasm/evmasm.py

Lines changed: 22 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,6 @@
1-
import collections
2-
3-
class memoized(object):
4-
'''Decorator. Caches a function's return value each time it is called.
5-
If called later with the same arguments, the cached value is returned
6-
(not reevaluated).
7-
'''
8-
9-
def __init__(self, func):
10-
self.func = func
11-
self.cache = {}
12-
13-
def __call__(self, *args, **kwargs):
14-
key = args + tuple(sorted(kwargs.items()))
15-
if not isinstance(key, collections.Hashable):
16-
# uncacheable. a list, for instance.
17-
# better to not cache than blow up.
18-
return self.func(*args, **kwargs)
19-
if key in self.cache:
20-
return self.cache[key]
21-
else:
22-
value = self.func(*args, **kwargs)
23-
self.cache[key] = value
24-
return value
25-
26-
def __repr__(self):
27-
'''Return the function's docstring.'''
28-
return self.func.__doc__
29-
30-
def __get__(self, obj, objtype):
31-
'''Support instance methods.'''
32-
return functools.partial(self.__call__, obj)
1+
from builtins import map, next, chr, range, object
2+
from binascii import hexlify, unhexlify
3+
from .util import memoized
334

345

356
class EVMAsm(object):
@@ -38,7 +9,7 @@ class EVMAsm(object):
389
3910
Example use::
4011
41-
>>> from manticore.platforms.evm import EVMAsm
12+
>>> from evmasm import EVMAsm
4213
>>> EVMAsm.disassemble_one('\\x60\\x10')
4314
Instruction(0x60, 'PUSH', 1, 0, 1, 0, 'Place 1 byte item on stack.', 16, 0)
4415
>>> EVMAsm.assemble_one('PUSH1 0x10')
@@ -221,7 +192,7 @@ def bytes(self):
221192
''' Encoded instruction '''
222193
bytes = []
223194
bytes.append(chr(self._opcode))
224-
for offset in reversed(xrange(self.operand_size)):
195+
for offset in reversed(range(self.operand_size)):
225196
c = (self.operand >> offset * 8) & 0xff
226197
bytes.append(chr(c))
227198
return ''.join(bytes)
@@ -470,7 +441,7 @@ def is_arithmetic(self):
470441
def _get_reverse_table():
471442
''' Build an internal table used in the assembler '''
472443
reverse_table = {}
473-
for (opcode, (name, immediate_operand_size, pops, pushes, gas, description)) in EVMAsm._table.items():
444+
for (opcode, (name, immediate_operand_size, pops, pushes, gas, description)) in list(EVMAsm._table.items()):
474445
mnemonic = name
475446
if name == 'PUSH':
476447
mnemonic = '%s%d' % (name, (opcode & 0x1f) + 1)
@@ -485,7 +456,7 @@ def assemble_one(assembler, pc=0):
485456
''' Assemble one EVM instruction from its textual representation.
486457
487458
:param assembler: assembler code for one instruction
488-
:param pc: program counter of the instruction (optional)
459+
:param pc: program counter of the instruction(optional)
489460
:return: An Instruction object
490461
491462
Example use::
@@ -506,17 +477,15 @@ def assemble_one(assembler, pc=0):
506477
operand = None
507478

508479
return EVMAsm.Instruction(opcode, name, operand_size, pops, pushes, gas, description, operand=operand, pc=pc)
509-
except Exception as e:
510-
print "Exception", repr(e)
511-
480+
except BaseException:
512481
raise Exception("Something wrong at pc %d" % pc)
513482

514483
@staticmethod
515484
def assemble_all(assembler, pc=0):
516485
''' Assemble a sequence of textual representation of EVM instructions
517486
518487
:param assembler: assembler code for any number of instructions
519-
:param pc: program counter of the first instruction (optional)
488+
:param pc: program counter of the first instruction(optional)
520489
:return: An generator of Instruction objects
521490
522491
Example use::
@@ -550,7 +519,7 @@ def disassemble_one(bytecode, pc=0):
550519
551520
:param bytecode: the bytecode stream
552521
:type bytecode: bytearray or str
553-
:param pc: program counter of the instruction (optional)
522+
:param pc: program counter of the instruction(optional)
554523
:type bytecode: iterator/sequence/str
555524
:return: an Instruction object
556525
@@ -559,11 +528,11 @@ def disassemble_one(bytecode, pc=0):
559528
>>> print EVMAsm.disassemble_one('\x60\x10')
560529
561530
'''
562-
if isinstance(bytecode, str):
563-
bytecode = bytearray(bytecode)
531+
if isinstance(bytecode, (str, bytes)):
532+
bytecode = bytearray(bytecode.encode())
564533
bytecode = iter(bytecode)
565534
opcode = next(bytecode)
566-
assert isinstance(opcode, (int, long))
535+
assert isinstance(opcode, int)
567536

568537
invalid = ('INVALID', 0, 0, 0, 0, 'Unknown opcode')
569538
name, operand_size, pops, pushes, gas, description = EVMAsm._table.get(opcode, invalid)
@@ -578,7 +547,7 @@ def disassemble_all(bytecode, pc=0):
578547
''' Decode all instructions in bytecode
579548
580549
:param bytecode: an evm bytecode (binary)
581-
:param pc: program counter of the first instruction (optional)
550+
:param pc: program counter of the first instruction(optional)
582551
:type bytecode: iterator/sequence/str
583552
:return: An generator of Instruction objects
584553
@@ -603,7 +572,7 @@ def disassemble_all(bytecode, pc=0):
603572
'''
604573

605574
if isinstance(bytecode, str):
606-
bytecode = bytearray(bytecode)
575+
bytecode = bytearray(bytecode.encode())
607576
bytecode = iter(bytecode)
608577
while True:
609578
instr = EVMAsm.disassemble_one(bytecode, pc=pc)
@@ -615,7 +584,7 @@ def disassemble(bytecode, pc=0):
615584
''' Disassemble an EVM bytecode
616585
617586
:param bytecode: binary representation of an evm bytecode (hexadecimal)
618-
:param pc: program counter of the first instruction (optional)
587+
:param pc: program counter of the first instruction(optional)
619588
:type bytecode: str
620589
:return: the text representation of the aseembler code
621590
@@ -637,7 +606,7 @@ def assemble(asmcode, pc=0):
637606
''' Assemble an EVM program
638607
639608
:param asmcode: an evm assembler program
640-
:param pc: program counter of the first instruction (optional)
609+
:param pc: program counter of the first instruction(optional)
641610
:type asmcode: str
642611
:return: the hex representation of the bytecode
643612
@@ -653,14 +622,14 @@ def assemble(asmcode, pc=0):
653622
...
654623
"\x60\x60\x60\x40\x52\x60\x02\x61\x01\x00"
655624
'''
656-
return ''.join(map(lambda x: x.bytes, EVMAsm.assemble_all(asmcode, pc=pc)))
625+
return ''.join([x.bytes for x in EVMAsm.assemble_all(asmcode, pc=pc)])
657626

658627
@staticmethod
659628
def disassemble_hex(bytecode, pc=0):
660629
''' Disassemble an EVM bytecode
661630
662631
:param bytecode: canonical representation of an evm bytecode (hexadecimal)
663-
:param pc: program counter of the first instruction (optional)
632+
:param pc: program counter of the first instruction(optional)
664633
:type bytecode: str
665634
:return: the text representation of the aseembler code
666635
@@ -677,15 +646,15 @@ def disassemble_hex(bytecode, pc=0):
677646
'''
678647
if bytecode.startswith('0x'):
679648
bytecode = bytecode[2:]
680-
bytecode = bytecode.decode('hex')
649+
bytecode = unhexlify(bytecode.encode())
681650
return EVMAsm.disassemble(bytecode, pc=pc)
682651

683652
@staticmethod
684653
def assemble_hex(asmcode, pc=0):
685654
''' Assemble an EVM program
686655
687656
:param asmcode: an evm assembler program
688-
:param pc: program counter of the first instruction (optional)
657+
:param pc: program counter of the first instruction(optional)
689658
:type asmcode: str
690659
:return: the hex representation of the bytecode
691660
@@ -701,4 +670,4 @@ def assemble_hex(asmcode, pc=0):
701670
...
702671
"0x6060604052600261010"
703672
'''
704-
return '0x' + EVMAsm.assemble(asmcode, pc=pc).encode('hex')
673+
return '0x' + hexlify(EVMAsm.assemble(asmcode, pc=pc).encode()).decode()

0 commit comments

Comments
 (0)