-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathutils.py
122 lines (92 loc) · 2.94 KB
/
utils.py
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
""" various utilities """
import opcodes as opc
INT_LIMIT = 2 ** 31
def read_bytes(filename):
""" generator yielding bytes from a file """
with open(filename, "rb") as file_h:
while True:
chunk = file_h.read()
if chunk:
for byte in chunk:
yield ord(byte)
else:
break
def get_pyc_list(filename):
""" get the pyc file as a list of bytes """
lst = list(read_bytes(filename))
return lst
def show_pyc(lst):
""" shows the pyclist in hex format """
return [hex(num) for num in lst]
def decimal(pyc_list, cur, num_byte=2):
""" compute the decimal value of the num_byte little endian hex """
value = 0
factor = 0
for idx in range(num_byte):
value |= pyc_list[cur+idx+1] << factor
factor += 8
if value >= INT_LIMIT:
value = value - 2 * INT_LIMIT
return value
def start_of_code(pyc_list, cur=0):
""" find the start of the code segment """
while (pyc_list[cur] != opc.TYPE_CODE and
pyc_list[cur+17] != opc.TYPE_STRING):
cur += 1
if cur == len(pyc_list) - 1:
raise Exception("no code segment in the rest of the pyc")
return cur + 22
def skip_element(pycbuf, cur):
""" skips a code element like integer, t_string, etc """
leng = decimal(pycbuf, cur, 4)
return cur + leng + 5
def end_of_code(pyc_list, cur=0):
""" find the end of the current code """
cur += 17 # now cur is at byte code s:73 , start of the code string
cur = skip_element(pyc_list, cur) # skipping the code string
# skipping the co_consts field
n_const = decimal(pyc_list, cur, 4)
cur += 5
for dummy in range(n_const):
if pyc_list[cur] == opc.TYPE_INTEGER:
cur += 5
elif pyc_list[cur] == opc.TYPE_NONE:
cur += 1
elif pyc_list[cur] == opc.TYPE_CODE:
cur = end_of_code(pyc_list, cur)
else:
cur += 1
# skip 4 (:28 s that is co_names, varnames, cellvars, freevars
n_const = 0
while True:
if pyc_list[cur] == opc.TYPE_TUPLE:
n_const += 1
if n_const == 4:
break
cur += 1
cur += 5
# skip filenmae
cur = skip_element(pyc_list, cur)
# skip function name
cur = skip_element(pyc_list, cur)
# skip first line number
cur += 4
# skip lnotab
cur = skip_element(pyc_list, cur)
return cur
def have_arg(opcode):
""" checks the opcode has argument(oparg) or not """
if opcode < opc.HAVE_ARG:
return False
else:
return True
def is_func_def(cur, pycbuf):
""" checks whether it is a function definition """
if pycbuf[cur] == opc.LOAD_CONSTANT and pycbuf[cur+3] == opc.MAKE_FUNCTION:
return True
else:
return False
def get_op_arg(pycbuf, cur):
""" gets the oparg of the current opcode """
oparg = decimal(pycbuf, cur)
return oparg