[sre] Don't throw random exception when runtime shuts down (#15798)
[mono-project.git] / tools / offsets-tool-py / offsets-tool.py
blob64fdaf92b64548e255cbaf07a57dba7f9989b165
1 #!/usr/bin/env python3
3 from __future__ import print_function
4 import os
5 import sys
6 import argparse
7 import clang.cindex
9 IOS_DEFINES = ["HOST_DARWIN", "TARGET_MACH", "MONO_CROSS_COMPILE", "USE_MONO_CTX", "_XOPEN_SOURCE"]
11 class Target:
12 def __init__(self, arch, platform, others):
13 self.arch_define = arch
14 self.platform_define = platform
15 self.defines = others
17 def get_clang_args(self):
18 ret = []
19 if self.arch_define:
20 ret.append (self.arch_define)
21 if self.platform_define:
22 ret.append (self.platform_define)
23 if self.defines:
24 ret.extend (self.defines)
25 return ret
27 class TypeInfo:
28 def __init__(self, name, is_jit):
29 self.name = name
30 self.is_jit = is_jit
31 self.size = -1
32 self.fields = []
34 class FieldInfo:
35 def __init__(self, name, offset):
36 self.name = name
37 self.offset = offset
39 class OffsetsTool:
40 def __init__(self):
41 pass
43 def parse_args(self):
44 def require_sysroot (args):
45 if not args.sysroot:
46 print ("Sysroot dir for device not set.", file=sys.stderr)
47 sys.exit (1)
49 def require_emscipten_path (args):
50 if not args.emscripten_path:
51 print ("Emscripten sdk dir not set.", file=sys.stderr)
52 sys.exit (1)
54 parser = argparse.ArgumentParser ()
55 parser.add_argument ('--libclang-path', dest='libclang_path', help='path to directory where libclang.{so,dylib} lives')
56 parser.add_argument ('--emscripten-sdk', dest='emscripten_path', help='path to emscripten sdk')
57 parser.add_argument ('--outfile', dest='outfile', help='path to output file', required=True)
58 parser.add_argument ('--monodir', dest='mono_path', help='path to mono source tree', required=True)
59 parser.add_argument ('--targetdir', dest='target_path', help='path to mono tree configured for target', required=True)
60 parser.add_argument ('--abi=', dest='abi', help='ABI triple to generate', required=True)
61 parser.add_argument ('--sysroot=', dest='sysroot', help='path to sysroot headers of target')
62 args = parser.parse_args ()
64 if not args.libclang_path or not os.path.isdir (args.libclang_path):
65 print ("Libclang path '" + args.libclang_path + "' doesn't exist.", file=sys.stderr)
66 sys.exit (1)
67 if not os.path.isdir (args.mono_path):
68 print ("Mono directory '" + args.mono_path + "' doesn't exist.", file=sys.stderr)
69 sys.exit (1)
70 if not os.path.isfile (args.target_path + "/config.h"):
71 print ("File '" + args.target_path + "/config.h' doesn't exist.", file=sys.stderr)
72 sys.exit (1)
74 self.sys_includes=[]
75 self.target = None
76 self.target_args = []
78 if "wasm" in args.abi:
79 require_emscipten_path (args)
80 self.sys_includes = [args.emscripten_path + "/system/include/libc"]
81 self.target = Target ("TARGET_WASM", None, [])
82 self.target_args += ["-target", args.abi]
84 elif "arm-apple-darwin10" == args.abi:
85 require_sysroot (args)
86 self.target = Target ("TARGET_ARM", "TARGET_IOS", ["ARM_FPU_VFP", "HAVE_ARMV5"] + IOS_DEFINES)
87 self.target_args += ["-arch", "arm"]
88 self.target_args += ["-isysroot", args.sysroot]
90 elif "aarch64-apple-darwin10" == args.abi:
91 require_sysroot (args)
92 self.target = Target ("TARGET_ARM64", "TARGET_IOS", IOS_DEFINES)
93 self.target_args += ["-arch", "arm64"]
94 self.target_args += ["-isysroot", args.sysroot]
96 elif "armv7k-apple-darwin" == args.abi:
97 require_sysroot (args)
98 self.target = Target ("TARGET_ARM", "TARGET_WATCHOS", ["ARM_FPU_VFP", "HAVE_ARMV5"] + IOS_DEFINES)
99 self.target_args += ["-arch", "armv7k"]
100 self.target_args += ["-isysroot", args.sysroot]
102 elif "aarch64-apple-darwin10_ilp32" == args.abi:
103 require_sysroot (args)
104 self.target = Target ("TARGET_ARM64", "TARGET_WATCHOS", ["MONO_ARCH_ILP32"] + IOS_DEFINES)
105 self.target_args += ["-arch", "arm64_32"]
106 self.target_args += ["-isysroot", args.sysroot]
109 if not self.target:
110 print ("ABI '" + args.abi + "' is not supported.", file=sys.stderr)
111 sys.exit (1)
113 self.args = args
116 # Collect size/alignment/offset information by running clang on files from the runtime
118 def run_clang(self):
119 args = self.args
121 self.runtime_types = {}
123 mono_includes = [
124 args.mono_path,
125 args.mono_path + "/mono",
126 args.mono_path + "/mono/eglib",
127 args.target_path,
128 args.target_path + "/mono/eglib"
131 self.basic_types = ["gint8", "gint16", "gint32", "gint64", "float", "double", "gpointer"]
132 self.runtime_type_names = [
133 "MonoObject",
134 "MonoClass",
135 "MonoVTable",
136 "MonoDelegate",
137 "MonoInternalThread",
138 "MonoMulticastDelegate",
139 "MonoTransparentProxy",
140 "MonoRealProxy",
141 "MonoRemoteClass",
142 "MonoArray",
143 "MonoArrayBounds",
144 "MonoSafeHandle",
145 "MonoHandleRef",
146 "MonoComInteropProxy",
147 "MonoString",
148 "MonoException",
149 "MonoTypedRef",
150 "MonoThreadsSync",
151 "SgenThreadInfo",
152 "SgenClientThreadInfo",
153 "MonoProfilerCallContext"
155 self.jit_type_names = [
156 "MonoLMF",
157 "MonoMethodRuntimeGenericContext",
158 "MonoJitTlsData",
159 "MonoGSharedVtMethodRuntimeInfo",
160 "MonoContinuation",
161 "MonoContext",
162 "MonoDelegateTrampInfo",
163 "GSharedVtCallInfo",
164 "SeqPointInfo",
165 "DynCallArgs",
166 "MonoLMFTramp",
167 "CallContext",
168 "MonoFtnDesc"
170 for name in self.runtime_type_names:
171 self.runtime_types [name] = TypeInfo (name, False)
172 for name in self.jit_type_names:
173 self.runtime_types [name] = TypeInfo (name, True)
175 self.basic_type_size = {}
176 self.basic_type_align = {}
178 srcfiles = ['mono/metadata/metadata-cross-helpers.c', 'mono/mini/mini-cross-helpers.c']
180 clang_args = []
181 clang_args += self.target_args
182 clang_args += ['-std=gnu99', '-DMONO_GENERATING_OFFSETS']
183 for include in self.sys_includes:
184 clang_args.append ("-I")
185 clang_args.append (include)
186 for include in mono_includes:
187 clang_args.append ("-I")
188 clang_args.append (include)
189 for define in self.target.get_clang_args ():
190 clang_args.append ("-D" + define)
192 clang.cindex.Config.set_library_path (args.libclang_path)
194 for srcfile in srcfiles:
195 src = args.mono_path + "/" + srcfile
196 file_args = clang_args[:]
197 if not 'mini' in src:
198 file_args.append ('-DHAVE_SGEN_GC')
199 file_args.append ('-DHAVE_MOVING_COLLECTOR')
200 is_jit = False
201 else:
202 is_jit = True
203 index = clang.cindex.Index.create()
204 print ("Running clang: " + ' '.join (file_args) + ' ' + src + '\n')
205 tu = index.parse (src, args = file_args)
206 for d in tu.diagnostics:
207 print (d)
208 if d.severity > 2:
209 sys.exit (1)
210 for c in tu.cursor.walk_preorder():
211 if c.kind != clang.cindex.CursorKind.STRUCT_DECL and c.kind != clang.cindex.CursorKind.TYPEDEF_DECL:
212 continue
213 name = c.spelling
214 if c.kind == clang.cindex.CursorKind.TYPEDEF_DECL:
215 for c2 in c.get_children ():
216 if c2.kind == clang.cindex.CursorKind.STRUCT_DECL:
217 c = c2
218 type = c.type
219 if "struct _" in name:
220 name = name [8:]
221 if len (name) > 0 and name [0] == '_':
222 name = name [1:]
223 if name in self.runtime_types:
224 rtype = self.runtime_types [name]
225 if rtype.is_jit != is_jit:
226 continue
227 if type.get_size () < 0:
228 continue
229 rtype.size = type.get_size ()
230 for child in c.get_children ():
231 if child.kind != clang.cindex.CursorKind.FIELD_DECL:
232 continue
233 if child.is_bitfield ():
234 continue
235 rtype.fields.append (FieldInfo (child.spelling, child.get_field_offsetof () // 8))
236 if c.spelling == "basic_types_struct":
237 for field in c.get_children ():
238 btype = field.spelling.replace ("_f", "")
239 self.basic_type_size [btype] = field.type.get_size ()
240 self.basic_type_align [btype] = field.type.get_align ()
242 def gen (self):
243 outfile = self.args.outfile
244 target = self.target
245 f = open (outfile, 'w')
246 f.write ("#ifndef USED_CROSS_COMPILER_OFFSETS\n")
247 if target.arch_define:
248 f.write ("#ifdef " + target.arch_define + "\n")
249 if target.platform_define:
250 f.write ("#ifdef " + target.platform_define + "\n")
251 f.write ("#ifndef HAVE_BOEHM_GC\n")
252 f.write ("#define HAS_CROSS_COMPILER_OFFSETS\n")
253 f.write ("#if defined (USE_CROSS_COMPILE_OFFSETS) || defined (MONO_CROSS_COMPILE)\n")
255 f.write ("#if !defined (DISABLE_METADATA_OFFSETS)\n")
256 f.write ("#define USED_CROSS_COMPILER_OFFSETS\n")
257 for btype in self.basic_types:
258 f.write ("DECL_ALIGN2(%s,%s)\n" % (btype, self.basic_type_align [btype]))
259 for btype in self.basic_types:
260 f.write ("DECL_SIZE2(%s,%s)\n" % (btype, self.basic_type_size [btype]))
261 for type_name in self.runtime_type_names:
262 type = self.runtime_types [type_name]
263 if type.size == -1:
264 continue
265 f.write ("DECL_SIZE2(%s,%s)\n" % (type.name, type.size))
266 for field in type.fields:
267 f.write ("DECL_OFFSET2(%s,%s,%s)\n" % (type.name, field.name, field.offset))
268 f.write ("#endif //disable metadata check\n")
270 f.write ("#ifndef DISABLE_JIT_OFFSETS\n")
271 f.write ("#define USED_CROSS_COMPILER_OFFSETS\n")
272 for type_name in self.jit_type_names:
273 type = self.runtime_types [type_name]
274 if type.size == -1:
275 continue
276 f.write ("DECL_SIZE2(%s,%s)\n" % (type.name, type.size))
277 for field in type.fields:
278 f.write ("DECL_OFFSET2(%s,%s,%s)\n" % (type.name, field.name, field.offset))
279 f.write ("#endif //disable jit check\n")
281 f.write ("#endif //cross compiler checks\n")
282 f.write ("#endif //gc check\n")
283 if target.arch_define:
284 f.write ("#endif //" + target.arch_define + "\n")
285 if target.platform_define:
286 f.write ("#endif //" + target.platform_define + "\n")
287 f.write ("#endif //USED_CROSS_COMPILER_OFFSETS check\n")
289 tool = OffsetsTool ()
290 tool.parse_args ()
291 tool.run_clang ()
292 tool.gen ()
294 # Local Variables:
295 # indent-tabs-mode: 1
296 # tab-width: 4
297 # End: