1
0
mirror of https://github.com/angr/pyvex synced 2026-06-21 13:47:01 +00:00
Files
2018-06-16 00:24:12 -07:00

147 lines
5.0 KiB
Python
Executable File

import re
import os
import sys
import cffi
import subprocess
import platform
import logging
l = logging.getLogger('cffier')
l.setLevel(logging.DEBUG)
def find_good_scan(questionable):
known_good = []
end_line = len(questionable)
while len(questionable):
ffi = cffi.FFI()
l.debug("scan - trying %d good and %d questionable", len(known_good), len(questionable))
candidate = known_good + questionable[:end_line]
failed_line = -1
try:
ffi.cdef('\n'.join(candidate))
known_good = candidate
questionable = questionable[end_line:]
end_line = len(questionable)
except AssertionError:
questionable = questionable[1:]
end_line = len(questionable)
except cffi.CDefError as e:
if '<cdef source string>' in str(e):
failed_line = int(str(e).split('\n')[-1].split(':')[1])-1
elif str(e).count(':') >= 2:
failed_line = int(str(e).split('\n')[1].split(':')[1])
failed_line_description = str(e).split('\n')[0]
idx1 = failed_line_description.index('"')
idx2 = failed_line_description.rindex('"')
failed_reason = failed_line_description[idx1+1:idx2]
for i in range(failed_line, -1, -1):
if failed_reason in candidate[i]:
failed_line = i
elif 'unrecognized construct' in str(e):
failed_line = int(str(e).split()[1][:-1])-1
elif 'end of input' in str(e):
end_line -= 1
else:
raise Exception("Unknown error")
except cffi.FFIError as e:
if str(e).count(':') >= 2:
failed_line = int(str(e).split('\n')[0].split(':')[1])-1
else:
raise Exception("Unknown error")
if failed_line != -1:
end_line = failed_line-len(known_good)
if end_line == 0:
questionable = questionable[1:]
end_line = len(questionable)
return known_good
def doit(vex_path):
cpplist = ['cl', 'cpp']
cpp = os.getenv("CPP")
if cpp:
cpplist.insert(0, cpp)
if platform.system() == 'Darwin':
cpplist.insert(0, "clang")
errs = []
for cpp in cpplist:
cmd = [cpp, '-I' + vex_path, os.path.join("pyvex_c", "pyvex.h")]
if cpp in ('cl', 'clang', 'gcc', 'cc', 'clang++', 'g++'):
cmd.append("-E")
try:
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
header, stderr = p.communicate()
try:
header = header.decode("utf-8")
stderr = stderr.decode("utf-8")
except UnicodeDecodeError:
# They don't have to be unicode on Windows
pass
if not header.strip() or p.returncode != 0:
errs.append((" ".join(cmd), p.returncode, stderr))
continue
else:
break
except OSError:
errs.append((" ".join(cmd), -1, "does not exist"))
continue
else:
l.warning("failed commands:\n" +
"\n".join("{} ({}) -- {}".format(*e) for e in errs))
raise Exception(
"Couldn't process pyvex headers." +
"Please set CPP environmental variable to local path of \"cpp\"." +
"Note that \"cpp\" and \"g++\" are different."
)
# header = vex_pp + pyvex_pp
linesep = '\r\n' if '\r\n' in header else '\n'
ffi_text = linesep.join(line for line in header.split(linesep) if '#' not in line and line.strip() != '' and 'jmp_buf' not in line)
ffi_text = re.sub('\{\s*\} NoOp;', '{ int DONOTUSE; } NoOp;', ffi_text)
ffi_text = re.sub('__attribute__\s*\(.*\)', '', ffi_text)
ffi_text = re.sub('__declspec\s*\([^\)]*\)', '', ffi_text)
ffi_text = ffi_text.replace('__const', 'const')
ffi_text = ffi_text.replace('__inline', '')
ffi_text = ffi_text.replace('__w64', '')
ffi_text = ffi_text.replace('__cdecl', '')
ffi_text = ffi_text.replace('__int64', 'long')
ffi_lines = ffi_text.split(linesep)
good = find_good_scan(ffi_lines)
good += ['extern VexControl vex_control;']
with open('pyvex/vex_ffi.py', 'w') as fp:
fp.write('ffi_str = """' + '\n'.join(good) + '"""\n')
fp.write('guest_offsets = ' + repr(get_guest_offsets(vex_path)) + '\n')
def get_guest_offsets(vex_path):
fname = os.path.join(vex_path, 'libvex_guest_offsets.h')
out = {}
with open(fname) as fp:
for line in fp:
if line.startswith('#define'):
_, names, val = line.split()
val = int(val, 0)
assert names.startswith('OFFSET_')
_, arch, reg = names.split('_', 2)
out[(arch, reg.lower())] = val
return out
if __name__ == '__main__':
import sys
logging.basicConfig(level=logging.DEBUG)
doit(sys.argv[1])