forked from 1uks/ld_preload_gen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
executable file
·155 lines (130 loc) · 5.08 KB
/
main.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env python2
import argparse
import tempfile
import os
import logging
import jinja2
from constants import DEFAULT_HEADERS, INCLUDE_PATHS
from pygccxml import parser
from pygccxml.declarations import matcher
from pygccxml.utils import loggers
loggers.cxx_parser.setLevel(logging.ERROR)
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
class Parser(object):
def __init__(self, filename):
self.filename = filename
self.ns = parser.parse([filename], parser.gccxml_configuration_t())[0]
def _remove_ns(self, string):
return string.strip().lstrip("::")
def _prettify(self, string):
return string.strip().lstrip("__")
def _no_restrict(self, string):
return string.replace("__restrict__", "")
def _prettify_type(self, string):
return self._prettify(self._remove_ns(self._no_restrict(string)))
def _is_struct(self, type):
while hasattr(type, "base"):
type = type.base
if hasattr(type, "declaration"):
if hasattr(type.declaration, "class_type"):
if type.declaration.class_type == "struct":
return True
return False
def yield_functions(self, func_names):
for func_name in func_names:
try:
func = self.ns.free_function(func_name)
except matcher.declaration_not_found_t:
continue
if not func.required_args:
args = [{"name": "", "type": "void"}]
else:
args = []
for arg in func.required_args:
type = self._prettify_type(arg.type.decl_string)
if self._is_struct(arg.type):
type = "struct " + type
args.append({
"name": self._prettify(arg.name),
"type": type,
})
header = func.location.file_name
for path in INCLUDE_PATHS: # refactor
if func.location.file_name.startswith(path):
header = header.rsplit(path)[1]
break
return_type = self._remove_ns(func.return_type.decl_string)
if self._is_struct(func.return_type):
return_type = "struct " + return_type
yield {
"name": self._remove_ns(func.name),
"return_type": return_type,
"header": header,
"args": args,
}
class CodeGenerator(object):
def __init__(self):
self.functions = []
def add_function(self, function):
self.functions.append(function)
def generate(self):
raise NotImplementedError
class CCodeGenerator(CodeGenerator):
def __init__(self):
self.env = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.join(BASE_DIR, "templates")),
trim_blocks=True,
)
self.env.filters["joinargs"] = self._joinargs
super(CCodeGenerator, self).__init__()
def _joinargs(self, func):
return ", ".join(" ".join(arg.values()) for arg in func["args"])
def generate(self):
typedef_tpl = self.env.get_template("typedef.tpl")
typedefs = []
impl_tpl = self.env.get_template("impl.tpl")
impl_variadic_tpl = self.env.get_template("impl_variadic.tpl")
impls = []
include_tpl = self.env.get_template("include.tpl")
includes = []
orig_cache_tpl = self.env.get_template("orig_cache.tpl")
orig_caches = []
has_variadic = False
for func in self.functions:
typedef = typedef_tpl.render(func=func)
typedefs.append(typedef)
if func["args"][-1]["type"] == "...": # variadic
impl = impl_variadic_tpl.render(func=func)
has_variadic = True
else:
orig_cache = orig_cache_tpl.render(func=func)
orig_caches.append(orig_cache)
impl = impl_tpl.render(func=func)
impls.append(impl)
include = include_tpl.render(func=func)
if include not in includes:
includes.append(include)
return self.env.get_template("source.tpl").render(
includes=includes, typedefs=typedefs, orig_caches=orig_caches, impls=impls, has_variadic=has_variadic
)
class RustCodeGenerator(CodeGenerator):
pass
def main(headers, funcs):
fd, tmpfile = tempfile.mkstemp(suffix=".h")
with os.fdopen(fd, "w") as fileobj:
fileobj.write("\n".join("#include <%s>" % header for header in headers))
try:
parser = Parser(tmpfile)
finally:
os.unlink(tmpfile)
generator = CCodeGenerator()
for func in parser.yield_functions(funcs):
generator.add_function(func)
print generator.generate()
if __name__ == "__main__":
argparser = argparse.ArgumentParser()
argparser.add_argument("-H", "--header", nargs="*", dest="headers",
default=DEFAULT_HEADERS)
argparser.add_argument("func", nargs="+")
args = argparser.parse_args()
main(args.headers, args.func)