#!/usr/bin/env python import sys, os, glob sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'script')) import mconfig settings = mconfig.settings_root settings.package_unix_name.value = 'substitute' c = settings.host_machine().c_tools() c.cc.required() c.dsymutil.required() settings.host_machine().will_need_darwin_target_conditionals() settings.add_setting_option('imaon2', '--with-imaon2', 'path to imaon2 (optional)', '') settings.add_setting_option('gen_dia', '--enable-recompile-dia', 'generate darwin-inject-asm.S', False, bool=True) settings.add_setting_option('enable_tests', '--enable-tests', 'tests!', False, bool=True) settings.add_setting_option('enable_ios_bootstrap', '--enable-ios-bootstrap', 'default: true if targeting iOS', lambda: settings.host_machine().is_ios(), bool=True) settings.add_setting_option('install_name', '--install-name', 'LC_ID_DYLIB', lambda: ['/usr/local/lib/libsubstitute.0.dylib', '/usr/lib/libsubstitute.0.dylib'][settings.host_machine().is_ios()]) ldid_tool = mconfig.CLITool('ldid', ['ldid'], 'LDID', settings.host_machine(), settings.host_machine().toolchains()) ldid_tool.optional_nocheck() asm_archs = [ ('x86_64', []), ('i386', []), ('arm', ['-marm']), ('arm64', []), # XXX ] asm_cflags = ['-Os', '-fno-stack-protector', '-isysroot', '/dev/null', '-fPIC'] asm_ldflags = ['-nostartfiles', '-nodefaultlibs'] machs = [] for name, cflags in asm_archs: mach = mconfig.Machine('asm-' + name, settings, 'for cross-compiling the inject baton', name + '-apple-darwin10') machs.append(mach) cc = mach.c_tools().cc cc.optional() def f(): if settings.gen_dia: cc.argv() mach_settings = settings[mach.name] mach_settings.cflags = cflags + asm_cflags + mach_settings.cflags mach_settings.ldflags = asm_ldflags + mach_settings.ldflags mconfig.post_parse_args_will_need.append(f) def wrong_ios(): if settings.enable_ios_bootstrap and not settings.host_machine().is_ios(): raise mconfig.DependencyNotFoundException("iOS bootstrap requires iOS, but the target doesn't seem to be iOS - if you're compiling without Xcode, please specify --target=armv7-apple-darwin10 or something like that") mconfig.post_parse_args_will_need.append(wrong_ios) mconfig.parse_args() #################################### mconfig.mark_safe_to_clean('(src)/generated/darwin-inject-asm.S', settings) if settings.enable_ios_bootstrap: mconfig.log('Will build iOS bootstrap.\n') if settings.enable_werror: for mach in machs + [settings.host_machine()]: settings[mach.name].cflags = ['-Werror'] + settings[mach.name].cflags # XXX this is a mess and wrong flags = ['-O3'] if settings.host_machine().is_ios(): flags.append('-miphoneos-version-min=8.0') for i in ('cflags', 'ldflags'): settings.host[i] = flags + settings.host[i] settings.host.cflags = ['-fvisibility=hidden'] + settings.host.cflags settings.host.ldflags = ['-dead_strip'] + settings.host.ldflags # todo make overridable? cc_argv = c.cc.argv() if 'armv7' in cc_argv or 'arm64' in cc_argv: settings.modify_link = lambda env: ( env['cmds'].append(ldid_tool.argv() + ['-S'+settings.src+'/ent.plist', env['outs'][0]]), env['ins'].append(settings.src+'/ent.plist') ) settings.host.debug_info = True settings.c_includes = ['(src)/lib', '(src)/substrate', '(src)/vendor'] emitter = settings.emitter def cb(fn): if fn.endswith('/objc.c'): return settings.specialize(obj_ldflag_sets=[('-lobjc',)]) return settings # Note: the order of darwin-inject-asm.o is significant. Per man page, ld is # guaranteed to link objects in order, which is necessary because # darwin-inject-asm.S does not itself ensure there is at least 0x4000 bytes of # executable stuff after inject_page_start (so that arm can remap into arm64). # By putting it at the beginning, we can just reuse the space for the rest of # the library rather than having to pad with zeroes. # (This only matters on 32-bit ARM, and the text segment is currently 0xa000 # bytes there, more than enough.) mconfig.build_and_link_c_objs( emitter, settings.host_machine(), settings.specialize(override_ldflags=['-install_name', settings.install_name] + settings.host.ldflags), 'dylib', '(out)/libsubstitute.dylib', [ '(src)/generated/darwin-inject-asm.S', '(src)/lib/darwin/find-syms.c', '(src)/lib/darwin/inject.c', '(src)/lib/darwin/interpose.c', '(src)/lib/darwin/objc-asm.S', '(src)/lib/darwin/objc.c', '(src)/lib/darwin/read.c', '(src)/lib/darwin/substrate-compat.c', '(src)/lib/darwin/execmem.c', '(src)/lib/cbit/vec.c', '(src)/lib/jump-dis.c', '(src)/lib/transform-dis.c', '(src)/lib/hook-functions.c', '(src)/lib/strerror.c', ], settings_cb=cb ) #settings.test = 'foo baz' emitter.add_command(settings, ['(out)/libsubstitute.0.dylib'], [], ['ln -nfs libsubstitute.dylib (out)/libsubstitute.0.dylib']) def o_to_bin(exe): bin = os.path.splitext(exe)[0] + '.bin' emitter.add_command(settings, [bin], [exe], ['segedit -extract __TEXT __text (outs[0]) (ins[0])']) return bin if settings.gen_dia: args = [] for (name, _cflags), mach in zip(asm_archs, machs): exe = '(out)/inject-asm-raw-%s' % (name,) bin = exe + '.bin' mconfig.build_and_link_c_objs(emitter, mach, settings.specialize( override_obj_fn='(out)/inject-asm-raw-%s.o' % (name,), override_ldflags=['-Wl,-order_file,(src)/lib/darwin/inject-asm-raw.order'] + settings[mach.name].ldflags, ), 'dylib', exe, ['(src)/lib/darwin/inject-asm-raw.c']) bin = o_to_bin(exe) args.extend([name, bin]) emitter.add_command(settings, ['(src)/generated/darwin-inject-asm.S'], ['(src)/script/gen-inject-asm.sh'] + args[1::2], [['(src)/script/gen-inject-asm.sh', '(outs[0])'] + args]) if settings.enable_tests: # just for quick testing for ofile, sfile, cflags, mach in [ ('insns-arm.o', 'insns-arm.S', [], machs[2]), ('insns-thumb2.o', 'insns-arm.S', ['-DTHUMB2'], machs[2]), ('insns-libz-arm.o', 'insns-libz-arm.S', [], machs[2]), ('insns-libz-thumb2.o', 'insns-libz-arm.S', ['-DTHUMB2'], machs[2]), ('transform-dis-cases-arm64.o', 'transform-dis-cases-arm64.S', [], machs[3]), ('transform-dis-cases-i386.o', 'transform-dis-cases-i386.S', [], machs[1]), ('transform-dis-cases-x86_64.o', 'transform-dis-cases-x86_64.S', [], machs[0]), ]: mconfig.build_c_objs(emitter, mach, settings.specialize(override_obj_fn='(out)/'+ofile), ['(src)/test/'+sfile]) o_to_bin('(out)/'+ofile) tests = [ ('find-syms', ['-std=c89']), ('find-syms-cpp', 'find-syms', ['-x', 'c++', '-std=c++98'], {'cpp': True}), ('substrate', ['-x', 'c++', '-std=c++98'], {'cpp': True}), ('imp-forwarding', [], ['-framework', 'Foundation', '-lobjc'], {'extra_objs': ['(out)/lib/darwin/objc-asm.o']}), ('objc-hook', [], ['-framework', 'Foundation']), ('interpose',), ('inject', {'extra_objs': ['(out)/lib/darwin/inject.o', '(out)/lib/darwin/read.o', '(out)/generated/darwin-inject-asm.o']}), ('pc-patch', {'extra_objs': ['(out)/lib/darwin/execmem.o']}), ('execmem', [], ['-segprot', '__TEST', 'rwx', 'rx'], {'extra_objs': ['(out)/lib/darwin/execmem.o']}), ('hook-functions', [], ['-segprot', '__TEST', 'rwx', 'rx']), ('posixspawn-hook',), ('htab',), ('vec', {'cpp': True, 'extra_objs': ['(out)/lib/cbit/vec.o']}), ('vec-c', 'vec', ['-x', 'c'], {'extra_objs': ['(out)/lib/cbit/vec.o']}), ] for arch, hdr, xdis, target in [ ('arm', 'arm/dis-arm.inc.h', 'dis_arm', 'arm'), ('thumb', 'arm/dis-thumb.inc.h', 'dis_thumb', 'arm'), ('thumb2', 'arm/dis-thumb2.inc.h', 'dis_thumb2', 'arm'), ('arm64', 'arm64/dis-main.inc.h', 'dis', 'arm64'), ('i386', 'x86/dis-main.inc.h', 'dis', 'i386'), ('x86_64', 'x86/dis-main.inc.h', 'dis', 'x86_64') ]: tests.append(('td-simple-'+arch, 'td-simple', ['-DHDR="%s"' % (hdr,), '-Dxdis='+xdis, '-DFORCE_TARGET_'+target])) tests.append(('jump-dis-'+arch, 'jump-dis', ['-O0', '-DFORCE_TARGET_'+target], {'extra_objs': ['(out)/lib/cbit/vec.o']})) tests.append(('transform-dis-'+arch, 'transform-dis', ['-O0', '-DFORCE_TARGET_'+target], {'extra_objs': ['(out)/lib/cbit/vec.o']})) for tup in tests: tup = list(tup) ibase = obase = tup.pop(0) cflags = ldflags = [] options = {} if tup and isinstance(tup[0], str): ibase = tup.pop(0) if tup and isinstance(tup[0], (list, tuple)): cflags = tup.pop(0) if tup and isinstance(tup[0], (list, tuple)): ldflags = tup.pop(0) if tup: options, = tup o = '(out)/test-'+obase cfile = glob.glob(settings.src+'/test/test-'+ibase+'.*')[0] mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings.specialize( override_cflags=cflags+settings.host.cflags, override_ldflags=ldflags+settings.host.ldflags, override_obj_fn=o+'.o', override_is_cxx=options.get('cxx', False), ), 'exec', o, [cfile], objs=options.get('extra_objs', [])+['(out)/libsubstitute.dylib']) mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings, 'dylib', '(out)/injected-test-dylib.dylib', ['(src)/test/injected-test-dylib.c']) if settings.enable_ios_bootstrap: mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings.specialize( override_cflags=['-fobjc-arc', '-Wno-unused-parameter']+settings.host.cflags, override_ldflags=['-framework', 'UIKit', '-framework', 'Foundation']+settings.host.ldflags, ), 'exec', '(out)/SafetyDance.app/SafetyDance', [ '(src)/darwin-bootstrap/safety-dance/AutoGrid.m', '(src)/darwin-bootstrap/safety-dance/main.m', ] ) emitter.add_command(settings, ['(out)/SafetyDance.app/Info.plist'], ['(src)/darwin-bootstrap/safety-dance/Info.plist'], ['plutil -convert binary1 -o (outs[0]) (ins[0])']) for out in ['Default.png', 'Default@2x.png']: emitter.add_command(settings, ['(out)/SafetyDance.app/'+out], ['(src)/darwin-bootstrap/safety-dance/white.png'], ['cp (ins[0]) (outs[0])']) emitter.add_command(settings, ['safety-dance'], list(filter(lambda out: '/safety-dance/' in out, emitter.all_outs)), [], phony=True) ls = ['(out)/libsubstitute.dylib'] for ty, out, ins, objs, ldf, cf in [ ('dylib', '(out)/posixspawn-hook.dylib', ['(src)/darwin-bootstrap/posixspawn-hook.c'], ls, ['-lbsm'], []), ('dylib', '(out)/bundle-loader.dylib', ['(src)/darwin-bootstrap/bundle-loader.c'], [], [], []), ('exec', '(out)/unrestrict', ['(src)/darwin-bootstrap/unrestrict.c'], ls, [], []), ('exec', '(out)/inject-into-launchd', ['(src)/darwin-bootstrap/inject-into-launchd.c'], ls, ['-framework', 'IOKit', '-framework', 'CoreFoundation'], []), ('exec', '(out)/substituted', ['(src)/darwin-bootstrap/substituted.m'], ls, ['-lbsm', '-framework', 'Foundation', '-framework', 'CoreFoundation'], ['-fobjc-arc']), ('dylib', '(out)/safemode-ui-hook.dylib', ['(src)/darwin-bootstrap/safemode-ui-hook.m'], ls, ['-framework', 'Foundation', '-framework', 'UIKit'], ['-fobjc-arc']), ]: mconfig.build_and_link_c_objs(emitter, settings.host_machine(), settings.specialize(override_ldflags=ldf+settings.host.ldflags, override_cflags=cf+settings.host.cflags), ty, out, ins, objs=objs) emitter.add_command(settings, ['all'], list(emitter.all_outs), [], phony=True) emitter.set_default_rule('all') mconfig.finish_and_emit()