mirror of
https://github.com/JonathanSalwan/Triton
synced 2026-08-17 10:23:04 -04:00
minor improvements/fixes for autocomplete generation + cmake integration
This commit is contained in:
parent
0a823bbebc
commit
1fd0afe791
6 changed files with 86 additions and 30 deletions
|
|
@ -16,6 +16,7 @@ option(INCBUILD "Increment the build number" OFF)
|
|||
option(KERNEL4 "Pin will run on a Linux's kernel v4" ON)
|
||||
option(PINTOOL "Build Triton with the Pin tool as tracer" OFF)
|
||||
option(PYTHON_BINDINGS "Enable Python bindings into the libtriton" ON)
|
||||
option(PYTHON_BINDINGS_AUTOCOMPLETE "Enable generation of triton_autocomplete module for IDE autocompletion" OFF)
|
||||
option(STATICLIB "Build a static library" OFF)
|
||||
option(Z3_INTERFACE "Use Z3 as SMT solver" ON)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,16 @@ add_custom_target(doc
|
|||
DEPENDS gen_doc_from_spec
|
||||
)
|
||||
|
||||
if(PYTHON_BINDINGS_AUTOCOMPLETE)
|
||||
add_custom_target(python_autocomplete
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/autocomplete/generate_autocomplete.py "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPENDS gen_doc_from_spec
|
||||
)
|
||||
|
||||
execute_process (COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/triton_autocomplete DESTINATION ${PYTHON_SITE_PACKAGES})
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||
|
|
|
|||
20
doc/autocomplete/example.py
Normal file
20
doc/autocomplete/example.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from __future__ import print_function
|
||||
# triton_autocomplete will raise an import error.
|
||||
# IDEs should still provide autocomplete based on
|
||||
# the triton_autocomplete module
|
||||
from triton import *
|
||||
try:
|
||||
from triton_autocomplete import *
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
ctx = TritonContext()
|
||||
# Set the arch
|
||||
ctx.setArchitecture(ARCH.X86)
|
||||
|
||||
inst = Instruction()
|
||||
inst.setAddress(0x40000)
|
||||
inst.setOpcode("\x89\xd0") # mov eax, edx
|
||||
ctx.processing(inst)
|
||||
print(inst)
|
||||
|
|
@ -1,7 +1,14 @@
|
|||
from typing import Dict, List
|
||||
try:
|
||||
from typing import Dict, List
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
class Function():
|
||||
generate_code = True
|
||||
INDENT_STR = ' ' * 4
|
||||
DEBUG = True
|
||||
|
||||
def __init__(self, name, args, ret_type, doc_str=''):
|
||||
# type: (str, Dict[str, str], str, str) -> None
|
||||
|
|
@ -11,16 +18,28 @@ class Function():
|
|||
self.ret_type = ret_type
|
||||
self.doc_str = doc_str
|
||||
|
||||
def gen_code(self):
|
||||
# type: () -> str
|
||||
code = ''
|
||||
func_call = '{}return self.org.{name}({args})'.format(self.INDENT_STR * 2, name=self.name,
|
||||
args=', '.join(self.args.keys()))
|
||||
|
||||
if self.DEBUG:
|
||||
code += "{}print({})\n".format(self.INDENT_STR * 2, repr(func_call.strip()))
|
||||
code += func_call
|
||||
|
||||
return code
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
func_str = '''
|
||||
@staticmethod
|
||||
def {fname}({arg_names}):
|
||||
# type: ({arg_types}) -> {ret_type}
|
||||
"""{doc_str}"""
|
||||
pass
|
||||
{code}
|
||||
'''.format(fname=self.name, ret_type=self.ret_type,
|
||||
arg_names=', '.join(self.args.keys()),
|
||||
arg_names=', '.join(['self'] + list(self.args.keys())),
|
||||
arg_types=', '.join('' if val == 'None' else val for val in self.args.values()),
|
||||
doc_str=self.doc_str)
|
||||
doc_str=self.doc_str,
|
||||
code='{}pass'.format(self.INDENT_STR * 2) if not self.generate_code else self.gen_code())
|
||||
return func_str
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
from typing import Optional, List, Dict, Tuple
|
||||
try:
|
||||
from typing import Optional, List, Dict, Tuple
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
import re
|
||||
import os
|
||||
|
|
@ -37,7 +40,9 @@ def sub_types(s):
|
|||
replacements = [
|
||||
('integer', 'int'),
|
||||
('string', 'str'),
|
||||
('void', 'None')
|
||||
('void', 'None'),
|
||||
('function', 'Callable'),
|
||||
('tuple', 'Tuple'),
|
||||
]
|
||||
for to_repl, repl in replacements:
|
||||
s = re.sub(to_repl, repl, s)
|
||||
|
|
@ -53,7 +58,7 @@ def sub_types(s):
|
|||
|
||||
def gen_function(sig, desc):
|
||||
# type: (str, str) -> Optional[Function]
|
||||
dbg = False and 'getPathConstraints' in sig
|
||||
dbg = False and 'land' in sig
|
||||
sig = sub_types(sig)
|
||||
sig_match = sig_re.search(sig)
|
||||
if not sig_match:
|
||||
|
|
@ -61,6 +66,11 @@ def gen_function(sig, desc):
|
|||
print("pattern: {}".format(sig_re.pattern))
|
||||
return None
|
||||
|
||||
# naming a function string... noice
|
||||
func_name = sig_match.group('name')
|
||||
if func_name == 'str':
|
||||
func_name = 'string'
|
||||
|
||||
if dbg:
|
||||
for i, g in enumerate(sig_match.groups()):
|
||||
print('group {}: {}'.format(i, g))
|
||||
|
|
@ -81,7 +91,7 @@ def gen_function(sig, desc):
|
|||
arg_name = ''
|
||||
# or it is a variable arg, which means we generate a generic str
|
||||
else:
|
||||
arg_name = '*args'
|
||||
arg_name = 'args'
|
||||
else:
|
||||
arg_name = arg_words[1]
|
||||
|
||||
|
|
@ -90,7 +100,7 @@ def gen_function(sig, desc):
|
|||
return None
|
||||
args[arg_name] = arg_type
|
||||
|
||||
return Function(sig_match.group('name'), args, sig_match.group('return'), desc)
|
||||
return Function(func_name, args, sig_match.group('return'), desc)
|
||||
|
||||
def gen_module_for_object(classname, input_str):
|
||||
# type: (str, str) -> str
|
||||
|
|
@ -114,9 +124,13 @@ def gen_module_for_object(classname, input_str):
|
|||
|
||||
# generate
|
||||
autogen_str = '''
|
||||
from typing import List, Union, overload
|
||||
from typing import List, Union, Callable, Tuple
|
||||
import triton
|
||||
|
||||
class {classname}:
|
||||
def __init__(self, *args, **kargs):
|
||||
self.org = triton.{classname}(*args, **kargs)
|
||||
|
||||
|
||||
{functions}
|
||||
'''.format(classname=classname, functions='\n'.join([str(f) for f in funcs]))
|
||||
|
|
@ -134,8 +148,9 @@ def gen_module_for_namespace(classname, input_str):
|
|||
if not matches:
|
||||
return ""
|
||||
|
||||
for i, match in enumerate(matches):
|
||||
member = ' {} = {}'.format(match.group('member'), i)
|
||||
for match in matches:
|
||||
member = ' {member} = triton.{namespace}.{member}'.format(
|
||||
member = match.group('member'), namespace=classname)
|
||||
members.append(member)
|
||||
|
||||
if not members:
|
||||
|
|
@ -144,6 +159,7 @@ def gen_module_for_namespace(classname, input_str):
|
|||
|
||||
# generate
|
||||
autogen_str = '''
|
||||
import triton
|
||||
class {classname}:
|
||||
|
||||
{members}
|
||||
|
|
@ -164,7 +180,7 @@ def gen_imports(objects, names):
|
|||
|
||||
def gen_init_file(objects, imports):
|
||||
# type: (List[Tuple[str, str]], List[str]) -> str
|
||||
return '\n'.join(imports)
|
||||
return '\n'.join(imports) + '\nraise ImportError\n'
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -173,11 +189,10 @@ def main():
|
|||
namespace_dir = os.path.join(src_dir, 'libtriton/bindings/python/namespaces')
|
||||
object_dir = os.path.join(src_dir, 'libtriton/bindings/python/objects')
|
||||
|
||||
out_dir = os.path.join(this_dir, 'triton_autocomplete')
|
||||
out_dir = os.path.join(this_dir if len(os.sys.argv) < 2 else os.sys.argv[1], 'triton_autocomplete')
|
||||
if not os.path.exists(out_dir):
|
||||
os.mkdir(out_dir)
|
||||
|
||||
|
||||
# get names/paths for objects
|
||||
obj_paths = glob(object_dir + '/*.cpp')
|
||||
objs = [] # type: List[Tuple[str, str]]
|
||||
|
|
@ -195,6 +210,10 @@ def main():
|
|||
name_paths = glob(namespace_dir + '/*.cpp')
|
||||
names = [] # type: List[Tuple[str, str]]
|
||||
for name_path in name_paths:
|
||||
|
||||
if 'initSyscallNamespace' in name_path:
|
||||
print("info: skipping {}".format(name_path))
|
||||
continue
|
||||
# find name of namespace from doxygen page command
|
||||
with open(name_path, 'r') as f:
|
||||
data = f.read()
|
||||
|
|
@ -219,8 +238,8 @@ def main():
|
|||
|
||||
# write output
|
||||
with open(os.path.join(out_dir, '{}_{}.py'.format(OBJECT_PREFIX, obj_name)), 'w') as f:
|
||||
f.write('\n'.join((imp for imp in imports if obj_name not in imp)) + '\n')
|
||||
f.write(mod_str)
|
||||
f.write('\n' + '\n'.join((imp for imp in imports if obj_name not in imp)) + '\n')
|
||||
|
||||
# generate modules for namespaces
|
||||
for name_path, name_name in names:
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
from __future__ import print_function
|
||||
# import triton
|
||||
|
||||
from triton_autocomplete import *
|
||||
|
||||
ctx = TritonContext()
|
||||
ctx.setArchitecture(ARCH.X86_64)
|
||||
ctx.setAstRepresentationMode(AST_REPRESENTATION.PYTHON)
|
||||
|
||||
# ctx = triton_import.TritonContext()
|
||||
# ctx.setConcreteMemoryValue()
|
||||
|
||||
print('Done')
|
||||
Loading…
Add table
Add a link
Reference in a new issue