[M108 Migration] Encrypt password field in AutoFill DB
[platform/framework/web/chromium-efl.git] / native_client / run.py
1 #!/usr/bin/python
2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 from __future__ import print_function
7
8 import argparse
9 import os
10 import subprocess
11 import sys
12 import tempfile
13
14 import pynacl.platform
15
16 # Target architecture for PNaCl can be set through the ``-arch``
17 # command-line argument, and when its value is ``env`` the following
18 # program environment variable is queried to figure out which
19 # architecture to target.
20 ARCH_ENV_VAR_NAME = 'PNACL_RUN_ARCH'
21
22 class Environment:
23   pass
24 env = Environment()
25
26 def SetupEnvironment():
27   # native_client/ directory
28   env.nacl_root = FindBaseDir()
29
30   env.toolchain_base = os.path.join(env.nacl_root,
31                                     'toolchain',
32                                     '%s_x86' % pynacl.platform.GetOS())
33
34   # Path to PNaCl toolchain
35   env.pnacl_base = os.path.join(env.toolchain_base, 'pnacl_newlib')
36
37   # QEMU
38   env.arm_root = os.path.join(env.toolchain_base, 'arm_trusted')
39   env.qemu_arm = os.path.join(env.arm_root, 'run_under_qemu_arm')
40
41   env.mips32_root = os.path.join(env.toolchain_base, 'mips_trusted')
42   env.qemu_mips32 = os.path.join(env.mips32_root, 'run_under_qemu_mips32')
43
44   # Path to 'readelf'
45   env.readelf = FindReadElf()
46
47   # Path to 'scons'
48   env.scons = os.path.join(env.nacl_root, 'scons')
49
50   # Library path for dynamic linker.
51   env.library_path = []
52
53   # Suppress -S -a
54   env.paranoid = False
55
56   # Only print commands, don't run them
57   env.dry_run = False
58
59   # Force a specific sel_ldr
60   env.force_sel_ldr = None
61
62   # Force a specific IRT
63   env.force_irt = None
64
65   # Don't print anything
66   env.quiet = False
67
68   # Arch (x86-32, x86-64, arm, mips32)
69   env.arch = None
70
71   # Trace in QEMU
72   env.trace = False
73
74   # Debug the nexe using the debug stub
75   env.debug = False
76
77   # PNaCl (as opposed to NaCl).
78   env.is_pnacl = False
79
80 def PrintBanner(output):
81   if not env.quiet:
82     lines = output.split('\n')
83     print('*' * 80)
84     for line in lines:
85       padding = ' ' * max(0, (80 - len(line)) // 2)
86       print(padding + output + padding)
87     print('*' * 80)
88
89
90 def PrintCommand(s):
91   if not env.quiet:
92     print()
93     print(s)
94     print()
95
96
97 def SetupArch(arch, allow_build=True):
98   '''Setup environment variables that require knowing the
99      architecture. We can only do this after we've seen the
100      nexe or once we've read -arch off the command-line.
101   '''
102   env.arch = arch
103   # Path to Native NaCl toolchain (glibc)
104   # MIPS does not have glibc support.
105   if arch != 'mips32':
106     toolchain_arch, tooldir_arch, libdir = {
107         'x86-32': ('x86', 'x86_64', 'lib32'),
108         'x86-64': ('x86', 'x86_64', 'lib'),
109         'arm': ('arm', 'arm', 'lib'),
110         }[arch]
111     env.nnacl_tooldir = os.path.join(env.toolchain_base,
112                                      'nacl_%s_glibc' % toolchain_arch,
113                                      '%s-nacl' % tooldir_arch)
114     env.nnacl_libdir = os.path.join(env.nnacl_tooldir, libdir)
115   env.sel_ldr = FindOrBuildSelLdr(allow_build=allow_build)
116   env.irt = FindOrBuildIRT(allow_build=allow_build)
117   if arch == 'arm':
118     env.elf_loader = FindOrBuildElfLoader(allow_build=allow_build)
119
120
121 def SetupLibC(arch, is_dynamic):
122   if is_dynamic:
123     if env.is_pnacl:
124       libdir = os.path.join(env.pnacl_base, 'lib-' + arch)
125     else:
126       libdir = env.nnacl_libdir
127     env.runnable_ld = os.path.join(libdir, 'runnable-ld.so')
128     env.library_path.append(libdir)
129
130
131 def main(argv):
132   SetupEnvironment()
133   return_code = 0
134
135   sel_ldr_options = []
136   # sel_ldr's "quiet" options need to come early in the command line
137   # to suppress noisy output from processing other options, like -Q.
138   sel_ldr_quiet_options = []
139   nexe, nexe_params = ArgSplit(argv[1:])
140
141   try:
142     if env.is_pnacl:
143       nexe = Translate(env.arch, nexe)
144
145     # Read the ELF file info
146     if env.is_pnacl and env.dry_run:
147       # In a dry run, we don't actually run pnacl-translate, so there is
148       # no nexe for readelf. Fill in the information manually.
149       arch = env.arch
150       is_dynamic = False
151       is_glibc_static = False
152     else:
153       arch, is_dynamic, is_glibc_static = ReadELFInfo(nexe)
154
155     # Add default sel_ldr options
156     if not env.paranoid:
157       # Enable mmap() for loading the nexe, so that 'perf' gives usable output.
158       # Note that this makes the sandbox unsafe if the mmap()'d nexe gets
159       # modified while sel_ldr is running.
160       os.environ['NACL_FAULT_INJECTION'] = \
161         'ELF_LOAD_BYPASS_DESCRIPTOR_SAFETY_CHECK=GF1/999'
162       sel_ldr_options += ['-a']
163       # -S signal handling is not supported on windows, but otherwise
164       # it is useful getting the address of crashes.
165       if not pynacl.platform.IsWindows():
166         sel_ldr_options += ['-S']
167       # X86-64 glibc static has validation problems without stub out (-s)
168       if arch == 'x86-64' and is_glibc_static:
169         sel_ldr_options += ['-s']
170     if env.quiet:
171       # Don't print sel_ldr logs
172       # These need to be at the start of the arglist for full effectiveness.
173       # -q means quiet most stderr warnings.
174       # -l /dev/null means log to /dev/null.
175       sel_ldr_quiet_options = ['-q', '-l', '/dev/null']
176     if env.debug:
177       # Disabling validation (-c) is used by the debug stub test.
178       # TODO(dschuff): remove if/when it's no longer necessary
179       sel_ldr_options += ['-c', '-c', '-g']
180
181     # Tell the user
182     if is_dynamic:
183       extra = 'DYNAMIC'
184     else:
185       extra = 'STATIC'
186     PrintBanner('%s is %s %s' % (os.path.basename(nexe),
187                                  arch.upper(), extra))
188
189     # Setup architecture-specific environment variables
190     SetupArch(arch)
191
192     # Setup LibC-specific environment variables
193     SetupLibC(arch, is_dynamic)
194
195     # Add IRT to sel_ldr options.
196     if env.irt:
197       sel_ldr_options += ['-B', env.irt]
198
199     # The NaCl dynamic loader prefers posixy paths.
200     nexe_path = os.path.abspath(nexe)
201     nexe_path = nexe_path.replace('\\', '/')
202     sel_ldr_nexe_args = [nexe_path] + nexe_params
203
204     if is_dynamic:
205       ld_library_path = ':'.join(env.library_path)
206       if arch == 'arm':
207         sel_ldr_nexe_args = [env.elf_loader, '--interp-prefix',
208                              env.nnacl_tooldir] + sel_ldr_nexe_args
209         sel_ldr_options += ['-E', 'LD_LIBRARY_PATH=' + ld_library_path]
210       else:
211         sel_ldr_nexe_args = [env.runnable_ld, '--library-path',
212                              ld_library_path] + sel_ldr_nexe_args
213
214     # Setup sel_ldr arguments.
215     sel_ldr_args = sel_ldr_options + ['--'] + sel_ldr_nexe_args
216
217     # Run sel_ldr!
218     retries = 0
219     try:
220       if hasattr(env, 'retries'):
221         retries = int(env.retries)
222     except ValueError:
223       pass
224     collate = env.collate or retries > 0
225     input = sys.stdin.read() if collate else None
226     for iter in range(1 + max(retries, 0)):
227       output = RunSelLdr(sel_ldr_args, quiet_args=sel_ldr_quiet_options,
228                          collate=collate, stdin_string=input)
229       if env.last_return_code < 128:
230         # If the application crashes, we expect a 128+ return code.
231         break
232     sys.stdout.write(output or '')
233     return_code = env.last_return_code
234   finally:
235     if env.is_pnacl:
236       # Clean up the .nexe that was created.
237       try:
238         os.remove(nexe)
239       except:
240         pass
241
242   return return_code
243
244
245 def RunSelLdr(args, quiet_args=[], collate=False, stdin_string=None):
246   """Run the sel_ldr command and optionally capture its output.
247
248   Args:
249     args: A string list containing the command and arguments.
250     collate: Whether to capture stdout+stderr (rather than passing
251         them through to the terminal).
252     stdin_string: Text to send to the command via stdin.  If None, stdin is
253         inherited from the caller.
254
255   Returns:
256     A string containing the concatenation of any captured stdout plus
257     any captured stderr.
258   """
259   prefix = []
260   # The bootstrap loader args (--r_debug, --reserved_at_zero) need to
261   # come before quiet_args.
262   bootstrap_loader_args = []
263   arch = pynacl.platform.GetArch3264()
264   if arch != pynacl.platform.ARCH3264_ARM and env.arch == 'arm':
265     prefix = [ env.qemu_arm, '-cpu', 'cortex-a9']
266     if env.trace:
267       prefix += ['-d', 'in_asm,op,exec,cpu']
268     args = ['-Q'] + args
269
270   if arch != pynacl.platform.ARCH3264_MIPS32 and env.arch == 'mips32':
271     prefix = [env.qemu_mips32]
272     if env.trace:
273       prefix += ['-d', 'in_asm,op,exec,cpu']
274     args = ['-Q'] + args
275
276   # Use the bootstrap loader on linux.
277   if pynacl.platform.IsLinux():
278     bootstrap = os.path.join(os.path.dirname(env.sel_ldr),
279                              'nacl_helper_bootstrap')
280     loader = [bootstrap, env.sel_ldr]
281     template_digits = 'X' * 16
282     bootstrap_loader_args = ['--r_debug=0x' + template_digits,
283                              '--reserved_at_zero=0x' + template_digits]
284   else:
285     loader = [env.sel_ldr]
286   return Run(prefix + loader + bootstrap_loader_args + quiet_args + args,
287              exit_on_failure=(not collate),
288              capture_stdout=collate, capture_stderr=collate,
289              stdin_string=stdin_string)
290
291
292 def FindOrBuildIRT(allow_build = True):
293   if env.force_irt:
294     if env.force_irt == 'none':
295       return None
296     elif env.force_irt == 'core':
297       flavors = ['irt_core']
298     else:
299       irt = env.force_irt
300       if not os.path.exists(irt):
301         Fatal('IRT not found: %s' % irt)
302       return irt
303   else:
304     flavors = ['irt_core']
305
306   irt_paths = []
307   for flavor in flavors:
308     path = os.path.join(env.nacl_root, 'scons-out',
309                         'nacl_irt-%s/staging/%s.nexe' % (env.arch, flavor))
310     irt_paths.append(path)
311
312   for path in irt_paths:
313     if os.path.exists(path):
314       return path
315
316   if allow_build:
317     PrintBanner('irt not found. Building it with scons.')
318     irt = irt_paths[0]
319     BuildIRT(flavors[0])
320     assert(env.dry_run or os.path.exists(irt))
321     return irt
322
323   return None
324
325 def BuildIRT(flavor):
326   args = ('platform=%s naclsdk_validate=0 ' +
327           'sysinfo=0 -j8 %s') % (env.arch, flavor)
328   args = args.split()
329   Run([env.scons] + args, cwd=env.nacl_root)
330
331 def FindOrBuildElfLoader(allow_build=True):
332   if env.force_elf_loader:
333     if env.force_elf_loader == 'none':
334       return None
335     if not os.path.exists(env.force_elf_loader):
336       Fatal('elf_loader.nexe not found: %s' % env.force_elf_loader)
337     return env.force_elf_loader
338
339   path = os.path.join(env.nacl_root, 'scons-out',
340                       'nacl-' + env.arch,
341                       'staging', 'elf_loader.nexe')
342   if os.path.exists(path):
343     return path
344
345   if allow_build:
346     PrintBanner('elf_loader not found.  Building it with scons.')
347     Run([env.scons, 'platform=' + env.arch,
348          'naclsdk_validate=0', 'sysinfo=0',
349          '-j8', 'elf_loader'],
350         cwd=env.nacl_root)
351     assert(env.dry_run or os.path.exists(path))
352     return path
353
354   return None
355
356 def FindOrBuildSelLdr(allow_build=True):
357   if env.force_sel_ldr:
358     if env.force_sel_ldr in ('dbg','opt'):
359       modes = [ env.force_sel_ldr ]
360     else:
361       sel_ldr = env.force_sel_ldr
362       if not os.path.exists(sel_ldr):
363         Fatal('sel_ldr not found: %s' % sel_ldr)
364       return sel_ldr
365   else:
366     modes = ['opt','dbg']
367
368   loaders = []
369   for mode in modes:
370     sel_ldr = os.path.join(
371         env.nacl_root, 'scons-out',
372         '%s-%s-%s' % (mode, pynacl.platform.GetOS(), env.arch),
373         'staging', 'sel_ldr')
374     if pynacl.platform.IsWindows():
375       sel_ldr += '.exe'
376     loaders.append(sel_ldr)
377
378   # If one exists, use it.
379   for sel_ldr in loaders:
380     if os.path.exists(sel_ldr):
381       return sel_ldr
382
383   # Build it
384   if allow_build:
385     PrintBanner('sel_ldr not found. Building it with scons.')
386     sel_ldr = loaders[0]
387     BuildSelLdr(modes[0])
388     assert(env.dry_run or os.path.exists(sel_ldr))
389     return sel_ldr
390
391   return None
392
393 def BuildSelLdr(mode):
394   args = ('platform=%s MODE=%s-host naclsdk_validate=0 ' +
395           'sysinfo=0 -j8 sel_ldr') % (env.arch, mode)
396   args = args.split()
397   Run([env.scons] + args, cwd=env.nacl_root)
398
399 def Translate(arch, pexe):
400   output_file = os.path.splitext(pexe)[0] + '.' + arch + '.nexe'
401   pnacl_translate = os.path.join(env.pnacl_base, 'bin', 'pnacl-translate')
402   args = [ pnacl_translate, '-arch', arch, pexe, '-o', output_file,
403            '--allow-llvm-bitcode-input' ]
404   Run(args)
405   return output_file
406
407 def Stringify(args):
408   ret = ''
409   for arg in args:
410     if ' ' in arg:
411       ret += ' "%s"' % arg
412     else:
413       ret += ' %s' % arg
414   return ret.strip()
415
416 def PrepareStdin(stdin_string):
417   """Prepare a stdin stream for a subprocess based on contents of a string.
418   This has to be in the form of an actual file, rather than directly piping
419   the string, since the child may (inappropriately) try to fseek() on stdin.
420
421   Args:
422     stdin_string: The characters to pipe to the subprocess.
423
424   Returns:
425     An open temporary file object ready to be read from.
426   """
427   f = tempfile.TemporaryFile()
428   f.write(stdin_string)
429   f.seek(0)
430   return f
431
432 def Run(args, cwd=None, verbose=True, exit_on_failure=False,
433         capture_stdout=False, capture_stderr=False, stdin_string=None):
434   """Run a command and optionally capture its output.
435
436   Args:
437     args: A string list containing the command and arguments.
438     cwd: Change to this directory before running.
439     verbose: Print the command before running it.
440     exit_on_failure: Exit immediately if the command returns nonzero.
441     capture_stdout: Capture the stdout as a string (rather than passing it
442         through to the terminal).
443     capture_stderr: Capture the stderr as a string (rather than passing it
444         through to the terminal).
445     stdin_string: Text to send to the command via stdin.  If None, stdin is
446         inherited from the caller.
447
448   Returns:
449     A string containing the concatenation of any captured stdout plus
450     any captured stderr.
451   """
452   if verbose:
453     PrintCommand(Stringify(args))
454     if env.dry_run:
455       return
456
457   stdout_redir = None
458   stderr_redir = None
459   stdin_redir = None
460   if capture_stdout:
461     stdout_redir = subprocess.PIPE
462   if capture_stderr:
463     stderr_redir = subprocess.PIPE
464   if stdin_string:
465     stdin_redir = PrepareStdin(stdin_string)
466
467   p = None
468   try:
469     # PNaCl toolchain executables (pnacl-translate, readelf) are scripts
470     # not binaries, so it doesn't want to run on Windows without a shell.
471     use_shell = True if pynacl.platform.IsWindows() else False
472     p = subprocess.Popen(args, stdin=stdin_redir, stdout=stdout_redir,
473                          stderr=stderr_redir, cwd=cwd, shell=use_shell,
474                          encoding='utf-8')
475     (stdout_contents, stderr_contents) = p.communicate()
476   except KeyboardInterrupt as e:
477     if p:
478       p.kill()
479     raise e
480   except BaseException as e:
481     if p:
482       p.kill()
483     raise e
484
485   env.last_return_code = p.returncode
486
487   if p.returncode != 0 and exit_on_failure:
488     if capture_stdout or capture_stderr:
489       # Print an extra message if any of the program's output wasn't
490       # going to the screen.
491       Fatal('Failed to run: %s' % Stringify(args))
492     sys.exit(p.returncode)
493
494   return (stdout_contents or '') + (stderr_contents or '')
495
496
497 def ArgSplit(argv):
498   """Parse command-line arguments.
499
500   Returns:
501     Tuple (nexe, nexe_args) where nexe is the name of the nexe or pexe
502     to execute, and nexe_args are its runtime arguments.
503   """
504   desc = ('Run a command-line nexe (or pexe). Automatically handles\n' +
505           'translation, building sel_ldr, and building the IRT.')
506   parser = argparse.ArgumentParser(description=desc)
507   parser.add_argument('-L', action='append', dest='library_path', default=[],
508                       help='Additional library path for dynamic linker.')
509   parser.add_argument('--paranoid', action='store_true', default=False,
510                       help='Remove -S (signals) and -a (file access) ' +
511                       'from the default sel_ldr options, and disallow mmap() ' +
512                       'for loading the nexe.')
513   parser.add_argument('--loader', dest='force_sel_ldr', metavar='SEL_LDR',
514                       help='Path to sel_ldr.  "dbg" or "opt" means use ' +
515                       'dbg or opt version of sel_ldr. ' +
516                       'By default, use whichever sel_ldr already exists; ' +
517                       'otherwise, build opt version.')
518   parser.add_argument('--irt', dest='force_irt', metavar='IRT',
519                       help='Path to IRT nexe.  "core" or "none" means use ' +
520                       'Core IRT or no IRT.  By default, use whichever IRT ' +
521                       'already exists; otherwise, build irt_core.')
522   parser.add_argument('--elf_loader', dest='force_elf_loader',
523                       metavar='ELF_LOADER',
524                       help='Path to elf_loader nexe.  ' +
525                       'By default find it in scons-out, or build it.')
526   parser.add_argument('--dry-run', '-n', action='store_true', default=False,
527                       help="Just print commands, don't execute them.")
528   parser.add_argument('--quiet', '-q', action='store_true', default=False,
529                       help="Don't print anything.")
530   parser.add_argument('--retries', default='0', metavar='N',
531                       help='Retry sel_ldr command up to N times (if ' +
532                       'flakiness is expected).  This argument implies ' +
533                       '--collate.')
534   parser.add_argument('--collate', action='store_true', default=False,
535                       help="Combine/collate sel_ldr's stdout and stderr, and " +
536                       "print to stdout.")
537   parser.add_argument('--trace', '-t', action='store_true', default=False,
538                       help='Trace qemu execution.')
539   parser.add_argument('--debug', '-g', action='store_true', default=False,
540                       help='Run sel_ldr with debugging enabled.')
541   parser.add_argument('-arch', '-m', dest='arch', action='store',
542                       choices=sorted(
543                         pynacl.platform.ARCH3264_LIST + ['env']),
544                       help=('Specify architecture for PNaCl translation. ' +
545                             '"env" is a special value which obtains the ' +
546                             'architecture from the environment ' +
547                             'variable "%s".') % ARCH_ENV_VAR_NAME)
548   parser.add_argument('remainder', nargs=argparse.REMAINDER,
549                       metavar='nexe/pexe + args')
550   (options, args) = parser.parse_known_args(argv)
551
552   # Copy the options into env.
553   for (key, value) in vars(options).items():
554     setattr(env, key, value)
555
556   args += options.remainder
557   nexe = args[0] if len(args) else ''
558   env.is_pnacl = nexe.endswith('.pexe')
559
560   if env.arch == 'env':
561     # Get the architecture from the environment.
562     try:
563       env.arch = os.environ[ARCH_ENV_VAR_NAME]
564     except Exception as e:
565       Fatal(('Option "-arch env" specified, but environment variable ' +
566             '"%s" not specified: %s') % (ARCH_ENV_VAR_NAME, e))
567   if not env.arch and env.is_pnacl:
568     # For NaCl we'll figure out the architecture from the nexe's
569     # architecture, but for PNaCl we first need to translate and the
570     # user didn't tell us which architecture to translate to. Be nice
571     # and just translate to the current machine's architecture.
572     env.arch = pynacl.platform.GetArch3264()
573   # Canonicalize env.arch.
574   env.arch = pynacl.platform.GetArch3264(env.arch)
575   return nexe, args[1:]
576
577
578 def Fatal(msg, *args):
579   if len(args) > 0:
580     msg = msg % args
581   print(msg)
582   sys.exit(1)
583
584
585 def FindReadElf():
586   '''Returns the path of "readelf" binary.'''
587
588   candidates = []
589   # Use PNaCl's if it available.
590   candidates.append(
591     os.path.join(env.pnacl_base, 'bin', 'pnacl-readelf'))
592
593   # Otherwise, look for the system readelf
594   for path in os.environ['PATH'].split(os.pathsep):
595     candidates.append(os.path.join(path, 'readelf'))
596
597   for readelf in candidates:
598     if os.path.exists(readelf):
599       return readelf
600
601   Fatal('Cannot find readelf!')
602
603
604 def ReadELFInfo(f):
605   ''' Returns: (arch, is_dynamic, is_glibc_static) '''
606
607   readelf = env.readelf
608   readelf_out = Run([readelf, '-lh', f], capture_stdout=True, verbose=False)
609
610   machine_line = None
611   is_dynamic = False
612   is_glibc_static = False
613   for line in readelf_out.split('\n'):
614     line = line.strip()
615     if line.startswith('Machine:'):
616       machine_line = line
617     if line.startswith('DYNAMIC'):
618       is_dynamic = True
619     if '__libc_atexit' in line:
620       is_glibc_static = True
621
622   if not machine_line:
623     Fatal('Script error: readelf output did not make sense!')
624
625   if 'Intel 80386' in machine_line:
626     arch = 'x86-32'
627   elif 'X86-64' in machine_line:
628     arch = 'x86-64'
629   elif 'ARM' in machine_line:
630     arch = 'arm'
631   elif 'MIPS' in machine_line:
632     arch = 'mips32'
633   else:
634     Fatal('%s: Unknown machine type', f)
635
636   return (arch, is_dynamic, is_glibc_static)
637
638
639 def FindBaseDir():
640   '''Crawl backwards, starting from the directory containing this script,
641      until we find the native_client/ directory.
642   '''
643
644   curdir = os.path.abspath(sys.argv[0])
645   while os.path.basename(curdir) != 'native_client':
646     curdir,subdir = os.path.split(curdir)
647     if subdir == '':
648       # We've hit the file system root
649       break
650
651   if os.path.basename(curdir) != 'native_client':
652     Fatal('Unable to find native_client directory!')
653   return curdir
654
655
656 if __name__ == '__main__':
657   sys.exit(main(sys.argv))