15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""A utility script to help building Syzygy-reordered Chrome binaries."""
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The default relink executable to use to reorder binaries.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_DEFAULT_RELINKER = os.path.join(
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.path.join(os.path.dirname(__file__), '../../../..'),
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    'third_party/syzygy/binaries/exe/relink.exe')
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_LOGGER = logging.getLogger()
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We use the same seed for all random reorderings to get a deterministic build.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_RANDOM_SEED = 1347344
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _Shell(*cmd, **kw):
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Shells out to "cmd". Returns a tuple of cmd's stdout, stderr."""
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _LOGGER.info('Running command "%s".', cmd)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prog = subprocess.Popen(cmd, **kw)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  stdout, stderr = prog.communicate()
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if prog.returncode != 0:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise RuntimeError('Command "%s" returned %d.' % (cmd, prog.returncode))
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return stdout, stderr
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _ReorderBinary(relink_exe, executable, symbol, destination_dir):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Reorders the executable found in input_dir, and writes the resultant
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reordered executable and symbol files to destination_dir.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  If a file named <executable>-order.json exists, imposes that order on the
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output binaries, otherwise orders them randomly.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cmd = [relink_exe,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         '--overwrite',
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         '--input-image=%s' % executable,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         '--input-pdb=%s' % symbol,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         '--output-image=%s' % os.path.abspath(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             os.path.join(destination_dir, os.path.basename(executable))),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         '--output-pdb=%s' % os.path.abspath(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             os.path.join(destination_dir, os.path.basename(symbol))),]
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Check whether there's an order file available for the executable.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  order_file = '%s-order.json' % executable
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if os.path.exists(order_file):
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # The ordering file exists, let's use that.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _LOGGER.info('Reordering "%s" according to "%s".',
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 os.path.basename(executable),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 os.path.basename(order_file))
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd.append('--order-file=%s' % order_file)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # No ordering file, we randomize the output.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _LOGGER.info('Randomly reordering "%s"', executable)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmd.append('--seed=%d' % _RANDOM_SEED)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return _Shell(*cmd)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(options):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logging.basicConfig(level=logging.INFO)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Make sure the destination directory exists.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not os.path.isdir(options.destination_dir):
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _LOGGER.info('Creating destination directory "%s".',
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 options.destination_dir)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.makedirs(options.destination_dir)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Reorder the binaries into the destination directory.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _ReorderBinary(options.relinker,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 options.input_executable,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 options.input_symbol,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 options.destination_dir)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _ParseOptions():
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser = optparse.OptionParser()
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--input_executable',
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      help='The path to the input executable.')
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--input_symbol',
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      help='The path to the input symbol file.')
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--relinker', default=_DEFAULT_RELINKER,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      help='Relinker exectuable to use, defaults to "%s"' % _DEFAULT_RELINKER)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('-d', '--destination_dir',
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      help='Destination directory for reordered files, defaults to '
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           'the subdirectory "reordered" in the output_dir.')
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = option_parser.parse_args()
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not options.input_executable:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    option_parser.error('You must provide an input executable.')
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not options.input_symbol:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    option_parser.error('You must provide an input symbol file.')
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not options.destination_dir:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options.destination_dir = os.path.join(options.output_dir, 'reordered')
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return options
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if '__main__' == __name__:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main(_ParseOptions()))
112