You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 09:22:40 +08:00
Start off with Anton Vorobyov's (DarkFenX) Python 3 scanner.
This commit is contained in:
@@ -118,7 +118,7 @@ class Scanner(object):
|
|||||||
print('%i\t%s\t' % (i, self.opc.opname[op]))
|
print('%i\t%s\t' % (i, self.opc.opname[op]))
|
||||||
|
|
||||||
def first_instr(self, start, end, instr, target=None, exact=True):
|
def first_instr(self, start, end, instr, target=None, exact=True):
|
||||||
'''
|
"""
|
||||||
Find the first <instr> in the block from start to end.
|
Find the first <instr> in the block from start to end.
|
||||||
<instr> is any python bytecode instruction or a list of opcodes
|
<instr> is any python bytecode instruction or a list of opcodes
|
||||||
If <instr> is an opcode with a target (like a jump), a target
|
If <instr> is an opcode with a target (like a jump), a target
|
||||||
@@ -127,32 +127,34 @@ class Scanner(object):
|
|||||||
closest to <target> will be returned.
|
closest to <target> will be returned.
|
||||||
|
|
||||||
Return index to it or None if not found.
|
Return index to it or None if not found.
|
||||||
'''
|
"""
|
||||||
code = self.code
|
code = self.code
|
||||||
assert(start>=0 and end<=len(code))
|
assert(start >= 0 and end <= len(code))
|
||||||
|
|
||||||
try: None in instr
|
try:
|
||||||
except: instr = [instr]
|
None in instr
|
||||||
|
except:
|
||||||
|
instr = [instr]
|
||||||
|
|
||||||
pos = None
|
result_offset = None
|
||||||
distance = len(code)
|
current_distance = len(code)
|
||||||
for i in self.op_range(start, end):
|
for offset in self.op_range(start, end):
|
||||||
op = code[i]
|
op = code[offset]
|
||||||
if op in instr:
|
if op in instr:
|
||||||
if target is None:
|
if target is None:
|
||||||
return i
|
return offset
|
||||||
dest = self.get_target(i, op)
|
dest = self.get_target(offset)
|
||||||
if dest == target:
|
if dest == target:
|
||||||
return i
|
return offset
|
||||||
elif not exact:
|
elif not exact:
|
||||||
_distance = abs(target - dest)
|
new_distance = abs(target - dest)
|
||||||
if _distance < distance:
|
if new_distance < current_distance:
|
||||||
distance = _distance
|
current_distance = new_distance
|
||||||
pos = i
|
result_offset = offset
|
||||||
return pos
|
return result_offset
|
||||||
|
|
||||||
def last_instr(self, start, end, instr, target=None, exact=True):
|
def last_instr(self, start, end, instr, target=None, exact=True):
|
||||||
'''
|
"""
|
||||||
Find the last <instr> in the block from start to end.
|
Find the last <instr> in the block from start to end.
|
||||||
<instr> is any python bytecode instruction or a list of opcodes
|
<instr> is any python bytecode instruction or a list of opcodes
|
||||||
If <instr> is an opcode with a target (like a jump), a target
|
If <instr> is an opcode with a target (like a jump), a target
|
||||||
@@ -161,65 +163,74 @@ class Scanner(object):
|
|||||||
closest to <target> will be returned.
|
closest to <target> will be returned.
|
||||||
|
|
||||||
Return index to it or None if not found.
|
Return index to it or None if not found.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
code = self.code
|
code = self.code
|
||||||
|
# Make sure requested positions do not go out of
|
||||||
|
# code bounds
|
||||||
if not (start>=0 and end<=len(code)):
|
if not (start>=0 and end<=len(code)):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try: None in instr
|
try:
|
||||||
except: instr = [instr]
|
None in instr
|
||||||
|
except:
|
||||||
|
instr = [instr]
|
||||||
|
|
||||||
pos = None
|
result_offset = None
|
||||||
distance = len(code)
|
current_distance = len(code)
|
||||||
for i in self.op_range(start, end):
|
for offset in self.op_range(start, end):
|
||||||
op = code[i]
|
op = code[offset]
|
||||||
if op in instr:
|
if op in instr:
|
||||||
if target is None:
|
if target is None:
|
||||||
pos = i
|
result_offset = offset
|
||||||
else:
|
else:
|
||||||
dest = self.get_target(i, op)
|
dest = self.get_target(offset)
|
||||||
if dest == target:
|
if dest == target:
|
||||||
distance = 0
|
current_distance = 0
|
||||||
pos = i
|
result_offset = offset
|
||||||
elif not exact:
|
elif not exact:
|
||||||
_distance = abs(target - dest)
|
new_distance = abs(target - dest)
|
||||||
if _distance <= distance:
|
if new_distance <= current_distance:
|
||||||
distance = _distance
|
current_distance = new_distance
|
||||||
pos = i
|
result_offset = offset
|
||||||
return pos
|
return result_offset
|
||||||
|
|
||||||
def all_instr(self, start, end, instr, target=None, include_beyond_target=False):
|
def all_instr(self, start, end, instr, target=None, include_beyond_target=False):
|
||||||
'''
|
"""
|
||||||
Find all <instr> in the block from start to end.
|
Find all <instr> in the block from start to end.
|
||||||
<instr> is any python bytecode instruction or a list of opcodes
|
<instr> is any python bytecode instruction or a list of opcodes
|
||||||
If <instr> is an opcode with a target (like a jump), a target
|
If <instr> is an opcode with a target (like a jump), a target
|
||||||
destination can be specified which must match precisely.
|
destination can be specified which must match precisely.
|
||||||
|
|
||||||
Return a list with indexes to them or [] if none found.
|
Return a list with indexes to them or [] if none found.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
code = self.code
|
code = self.code
|
||||||
assert(start>=0 and end<=len(code))
|
assert(start >= 0 and end <= len(code))
|
||||||
|
|
||||||
try: None in instr
|
try:
|
||||||
except: instr = [instr]
|
None in instr
|
||||||
|
except:
|
||||||
|
instr = [instr]
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for i in self.op_range(start, end):
|
for offset in self.op_range(start, end):
|
||||||
op = code[i]
|
op = code[offset]
|
||||||
if op in instr:
|
if op in instr:
|
||||||
if target is None:
|
if target is None:
|
||||||
result.append(i)
|
result.append(offset)
|
||||||
else:
|
else:
|
||||||
t = self.get_target(i, op)
|
t = self.get_target(offset)
|
||||||
if include_beyond_target and t >= target:
|
if include_beyond_target and t >= target:
|
||||||
result.append(i)
|
result.append(offset)
|
||||||
elif t == target:
|
elif t == target:
|
||||||
result.append(i)
|
result.append(offset)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def op_size(self, op):
|
def op_size(self, op):
|
||||||
|
"""
|
||||||
|
Return size of operator with its arguments
|
||||||
|
for given opcode <op>.
|
||||||
|
"""
|
||||||
if op < self.opc.HAVE_ARGUMENT and op not in self.opc.hasArgumentExtended:
|
if op < self.opc.HAVE_ARGUMENT and op not in self.opc.hasArgumentExtended:
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
@@ -229,6 +240,10 @@ class Scanner(object):
|
|||||||
return self.op_size(op) > 1
|
return self.op_size(op) > 1
|
||||||
|
|
||||||
def op_range(self, start, end):
|
def op_range(self, start, end):
|
||||||
|
"""
|
||||||
|
Iterate through positions of opcodes, skipping
|
||||||
|
arguments.
|
||||||
|
"""
|
||||||
while start < end:
|
while start < end:
|
||||||
yield start
|
yield start
|
||||||
start += self.op_size(self.code[start])
|
start += self.op_size(self.code[start])
|
||||||
@@ -243,14 +258,14 @@ class Scanner(object):
|
|||||||
return filtered
|
return filtered
|
||||||
|
|
||||||
def rem_or(self, start, end, instr, target=None, include_beyond_target=False):
|
def rem_or(self, start, end, instr, target=None, include_beyond_target=False):
|
||||||
'''
|
"""
|
||||||
Find all <instr> in the block from start to end.
|
Find all <instr> in the block from start to end.
|
||||||
<instr> is any python bytecode instruction or a list of opcodes
|
<instr> is any python bytecode instruction or a list of opcodes
|
||||||
If <instr> is an opcode with a target (like a jump), a target
|
If <instr> is an opcode with a target (like a jump), a target
|
||||||
destination can be specified which must match precisely.
|
destination can be specified which must match precisely.
|
||||||
|
|
||||||
Return a list with indexes to them or [] if none found.
|
Return a list with indexes to them or [] if none found.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
code = self.code
|
code = self.code
|
||||||
assert(start>=0 and end<=len(code))
|
assert(start>=0 and end<=len(code))
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user