diff --git a/util/mach/mig.py b/util/mach/mig.py new file mode 100755 index 00000000..2d248854 --- /dev/null +++ b/util/mach/mig.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# coding: utf-8 + +# Copyright 2014 The Crashpad Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import re +import subprocess +import sys + +def FixUserImplementation(implementation): + """Rewrites a MIG-generated user implementation (.c) file. + + Rewrites the file at |implementation| by adding “__attribute__((unused))” to + the definition of any structure typedefed as “__Reply” by searching for the + pattern unique to those structure definitions. These structures are in fact + unused in the user implementation file, and this will trigger a + -Wunused-local-typedefs warning in gcc unless removed or marked with the + “unused” attribute. + """ + + file = open(implementation, 'r+') + contents = file.read() + + pattern = re.compile('^(\t} __Reply);$', re.MULTILINE) + contents = pattern.sub(r'\1 __attribute__((unused));', contents) + + file.seek(0) + file.truncate() + file.write(contents) + file.close() + +def FixServerImplementation(implementation): + """Rewrites a MIG-generated server implementation (.c) file. + + Rewrites the file at |implementation| by replacing “mig_internal” with + “mig_external” on functions that begin with “__MIG_check__”. This makes these + functions available to other callers outside this file from a linkage + perspective. It then returns, as a list of lines, declarations that can be + added to a header file, so that other files that include that header file will + have access to these declarations from a compilation perspective. + """ + + file = open(implementation, 'r+') + contents = file.read() + + # Find interesting declarations. + declaration_pattern = \ + re.compile('^mig_internal (kern_return_t __MIG_check__.*)$', + re.MULTILINE) + declarations = declaration_pattern.findall(contents) + + # Remove “__attribute__((__unused__))” from the declarations, and call them + # “mig_external” or “extern” depending on whether “mig_external” is defined. + attribute_pattern = re.compile(r'__attribute__\(\(__unused__\)\) ') + declarations = ['#ifdef mig_external\nmig_external\n#else\nextern\n#endif\n' + + attribute_pattern.sub('', x) + + ';\n' for x in declarations] + + # Rewrite the declarations in this file as “mig_external”. + contents = declaration_pattern.sub(r'mig_external \1', contents); + + file.seek(0) + file.truncate() + file.write(contents) + file.close() + return declarations + +def FixHeader(header, declarations=[]): + """Rewrites a MIG-generated header (.h) file. + + Rewrites the file at |header| by placing it inside an “extern "C"” block, so + that it declares things properly when included by a C++ compilation unit. + |declarations| can be a list of additional declarations to place inside the + “extern "C"” block after the original contents of |header|. + """ + + file = open(header, 'r+') + contents = file.read() + declarations_text = ''.join(declarations) + contents = '''\ +#ifdef __cplusplus +extern "C" { +#endif + +%s +%s +#ifdef __cplusplus +} +#endif +''' % (contents, declarations_text) + file.seek(0) + file.truncate() + file.write(contents) + file.close() + +def main(args): + assert len(args) == 5 + (defs_file, user_c, server_c, user_h, server_h) = args + subprocess.check_call(['mig', + '-user', user_c, + '-server', server_c, + '-header', user_h, + '-sheader', server_h, + defs_file]) + FixUserImplementation(user_c) + server_declarations = FixServerImplementation(server_c) + FixHeader(user_h) + FixHeader(server_h, server_declarations) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/util/util.gyp b/util/util.gyp index 660e2a6d..951a7a77 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -81,6 +81,42 @@ 'stdlib/strnlen.cc', 'stdlib/strnlen.h', ], + 'actions': [ + { + 'action_name': 'mig exc.defs', + 'inputs': [ + 'mach/mig.py', + '$(SDKROOT)/usr/include/mach/exc.defs', + ], + 'outputs': [ + '<(INTERMEDIATE_DIR)/util/mach/excUser.c', + '<(INTERMEDIATE_DIR)/util/mach/excServer.c', + '<(INTERMEDIATE_DIR)/util/mach/exc.h', + '<(INTERMEDIATE_DIR)/util/mach/excServer.h', + ], + 'action': [ + 'python', '<@(_inputs)', '<@(_outputs)' + ], + 'process_outputs_as_sources': 1, + }, + { + 'action_name': 'mig mach_exc.defs', + 'inputs': [ + 'mach/mig.py', + '$(SDKROOT)/usr/include/mach/mach_exc.defs', + ], + 'outputs': [ + '<(INTERMEDIATE_DIR)/util/mach/mach_excUser.c', + '<(INTERMEDIATE_DIR)/util/mach/mach_excServer.c', + '<(INTERMEDIATE_DIR)/util/mach/mach_exc.h', + '<(INTERMEDIATE_DIR)/util/mach/mach_excServer.h', + ], + 'action': [ + 'python', '<@(_inputs)', '<@(_outputs)' + ], + 'process_outputs_as_sources': 1, + }, + ], }, { 'target_name': 'util_test_lib',