#!/usr/bin/env python # Copyright 2013 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Wrapper script for launching application within the sel_ldr. """ import argparse import os import subprocess import sys import create_nmf import getos SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) NACL_SDK_ROOT = os.path.dirname(SCRIPT_DIR) if sys.version_info < (2, 7, 0): sys.stderr.write("python 2.7 or later is required run this script\n") sys.exit(1) class Error(Exception): pass def Log(msg): if Log.verbose: sys.stderr.write(str(msg) + '\n') Log.verbose = False def FindQemu(): path = os.environ.get('PATH', '').split(os.pathsep) qemu_locations = [os.path.join(SCRIPT_DIR, 'qemu_arm'), os.path.join(SCRIPT_DIR, 'qemu-arm')] qemu_locations += [os.path.join(p, 'qemu_arm') for p in path] qemu_locations += [os.path.join(p, 'qemu-arm') for p in path] # See if qemu is in any of these locations. qemu_bin = None for loc in qemu_locations: if os.path.isfile(loc) and os.access(loc, os.X_OK): qemu_bin = loc break return qemu_bin def main(argv): epilog = 'Example: sel_ldr.py my_nexe.nexe' parser = argparse.ArgumentParser(description=__doc__, epilog=epilog) parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output') parser.add_argument('-d', '--debug', action='store_true', help='Enable debug stub') parser.add_argument('-e', '--exceptions', action='store_true', help='Enable exception handling interface') parser.add_argument('-p', '--passthrough-environment', action='store_true', help='Pass environment of host through to nexe') parser.add_argument('--debug-libs', action='store_true', help='Legacy option, do not use') parser.add_argument('--config', default='Release', help='Use a particular library configuration (normally ' 'Debug or Release)') parser.add_argument('executable', help='executable (.nexe) to run') parser.add_argument('args', nargs='*', help='argument to pass to exectuable') parser.add_argument('--library-path', help='Pass extra library paths') # To enable bash completion for this command first install optcomplete # and then add this line to your .bashrc: # complete -F _optcomplete sel_ldr.py try: import optcomplete optcomplete.autocomplete(parser) except ImportError: pass options = parser.parse_args(argv) if options.verbose: Log.verbose = True osname = getos.GetPlatform() if not os.path.exists(options.executable): raise Error('executable not found: %s' % options.executable) if not os.path.isfile(options.executable): raise Error('not a file: %s' % options.executable) elf_arch, dynamic = create_nmf.ParseElfHeader(options.executable) if elf_arch == 'arm' and osname != 'linux': raise Error('Cannot run ARM executables under sel_ldr on ' + osname) arch_suffix = elf_arch.replace('-', '_') sel_ldr = os.path.join(SCRIPT_DIR, 'sel_ldr_%s' % arch_suffix) irt = os.path.join(SCRIPT_DIR, 'irt_core_%s.nexe' % arch_suffix) if osname == 'win': sel_ldr += '.exe' Log('ROOT = %s' % NACL_SDK_ROOT) Log('SEL_LDR = %s' % sel_ldr) Log('IRT = %s' % irt) cmd = [sel_ldr] if osname == 'linux': # Run sel_ldr under nacl_helper_bootstrap helper = os.path.join(SCRIPT_DIR, 'nacl_helper_bootstrap_%s' % arch_suffix) Log('HELPER = %s' % helper) cmd.insert(0, helper) cmd.append('--r_debug=0xXXXXXXXXXXXXXXXX') cmd.append('--reserved_at_zero=0xXXXXXXXXXXXXXXXX') # This script is provided mostly as way to run binaries during testing, not # to run untrusted code in a production environment. As such we want it be # as invisible as possible. So we pass -q (quiet) to disable most of output # of sel_ldr itself, and -a (disable ACL) to enable local filesystem access. cmd += ['-q', '-a', '-B', irt] # Set the default NACLVERBOSITY level LOG_ERROR (-3). This can still be # overridden in the environment if debug information is desired. However # in most cases we don't want the application stdout/stderr polluted with # sel_ldr logging. if 'NACLVERBOSITY' not in os.environ and not options.verbose: os.environ['NACLVERBOSITY'] = "-3" if options.debug: cmd.append('-g') if options.exceptions: cmd.append('-e') if options.passthrough_environment: cmd.append('-p') if elf_arch == 'arm': # Use the QEMU arm emulator if available. qemu_bin = FindQemu() if not qemu_bin: raise Error('Cannot run ARM executables under sel_ldr without an emulator' '. Try installing QEMU (http://wiki.qemu.org/).') arm_libpath = os.path.join(NACL_SDK_ROOT, 'tools', 'lib', 'arm_trusted') if not os.path.isdir(arm_libpath): raise Error('Could not find ARM library path: %s' % arm_libpath) qemu = [qemu_bin, '-cpu', 'cortex-a8', '-L', arm_libpath] # '-Q' disables platform qualification, allowing arm binaries to run. cmd = qemu + cmd + ['-Q'] if dynamic: if options.debug_libs: sys.stderr.write('warning: --debug-libs is deprecated (use --config).\n') options.config = 'Debug' sdk_lib_dir = os.path.join(NACL_SDK_ROOT, 'lib', 'glibc_%s' % arch_suffix, options.config) if elf_arch == 'x86-64': lib_subdir = 'lib' tcarch = 'x86' tcsubarch = 'x86_64' usr_arch = 'x86_64' elif elf_arch == 'arm': lib_subdir = 'lib' tcarch = 'arm' tcsubarch = 'arm' usr_arch = 'arm' elif elf_arch == 'x86-32': lib_subdir = 'lib32' tcarch = 'x86' tcsubarch = 'x86_64' usr_arch = 'i686' else: raise Error("Unknown arch: %s" % elf_arch) toolchain = '%s_%s_glibc' % (osname, tcarch) toolchain_dir = os.path.join(NACL_SDK_ROOT, 'toolchain', toolchain) interp_prefix = os.path.join(toolchain_dir, tcsubarch + '-nacl') lib_dir = os.path.join(interp_prefix, lib_subdir) usr_lib_dir = os.path.join(toolchain_dir, usr_arch + '-nacl', 'usr', 'lib') libpath = [usr_lib_dir, sdk_lib_dir, lib_dir] if options.config not in ['Debug', 'Release']: config_fallback = 'Release' if 'Debug' in options.config: config_fallback = 'Debug' libpath.append(os.path.join(NACL_SDK_ROOT, 'lib', 'glibc_%s' % arch_suffix, config_fallback)) if options.library_path: libpath.extend([os.path.abspath(p) for p in options.library_path.split(':')]) libpath = ':'.join(libpath) if elf_arch == 'arm': ldso = os.path.join(SCRIPT_DIR, 'elf_loader_arm.nexe') cmd.append('-E') cmd.append('LD_LIBRARY_PATH=%s' % libpath) cmd.append(ldso) cmd.append('--interp-prefix') cmd.append(interp_prefix) else: ldso = os.path.join(lib_dir, 'runnable-ld.so') cmd.append(ldso) cmd.append('--library-path') cmd.append(libpath) Log('dynamic loader = %s' % ldso) # Append arguments for the executable itself. cmd.append(options.executable) cmd += options.args Log(cmd) return subprocess.call(cmd) if __name__ == '__main__': try: sys.exit(main(sys.argv[1:])) except Error as e: sys.stderr.write(str(e) + '\n') sys.exit(1)