def testGetSymbolToSectionsMap(self):
   processor = cyglog_to_orderfile.ObjectFileProcessor(None)
   processor._GetAllSymbolInfos = lambda: [
       SectionTestSymbol('.LTHUNK.foobar', 'unused'),
       SectionTestSymbol('_Znwj', '.text._Znwj'),
       SectionTestSymbol(  # Ctor/Dtor same name.
           '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev',
           '.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev'),
       SectionTestSymbol(
           '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev',
           '.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED2Ev'),
       SectionTestSymbol( # Ctor/Dtor different name.
           '_ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev',
           ('.text. _ZNSt3__119istreambuf2_iteratorIcNS_11char_'
            'traitsIcEEEC1Ev')),
       SectionTestSymbol(
           '_ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev',
           '.text._ZNSt3__119foo_iteratorIcNS_11char_traitsIcEEEC1Ev'),
       SectionTestSymbol('_AssemblyFunction', '.text'),
       SectionTestSymbol('_UnknownSection', '.surprise._UnknownSection'),
       SectionTestSymbol('_Znwj', '.text._another_section_for_Znwj')]
   self.assertDictWithUnorderedListEqual(
       {'_Znwj': ['.text._Znwj', '.text._another_section_for_Znwj'],
        # Ctor/Dtor same name.
        '_ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev':
        ['.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED1Ev',
         '.text._ZNSt3__119istreambuf_iteratorIcNS_11char_traitsIcEEED2Ev'],
        # Ctor/Dtor different name; a warning is emitted but the sections are
        # still added to the map.
        '_ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev':
        ['.text. _ZNSt3__119istreambuf2_iteratorIcNS_11char_traitsIcEEEC1Ev',
         '.text._ZNSt3__119foo_iteratorIcNS_11char_traitsIcEEEC1Ev'],
       },
       processor.GetSymbolToSectionsMap())
Beispiel #2
0
def GeneratePatchedOrderfile(unpatched_orderfile, native_lib_filename,
                             output_filename):
  """Writes a patched orderfile.

  Args:
    unpatched_orderfile: (str) Path to the unpatched orderfile.
    native_lib_filename: (str) Path to the native library.
    output_filename: (str) Path to the patched orderfile.
  """
  (offset_to_symbol_infos, name_to_symbol_infos) = _GroupSymbolInfosFromBinary(
      native_lib_filename)
  obj_dir = cygprofile_utils.GetObjDir(native_lib_filename)
  raw_symbol_map = cyglog_to_orderfile.ObjectFileProcessor(
      obj_dir).GetSymbolToSectionsMap()
  suffixed = _SectionsWithSuffixes(raw_symbol_map)
  symbol_to_sections_map = _CombineSectionListsByPrimaryName(raw_symbol_map)
  section_to_symbols_map = cygprofile_utils.InvertMapping(
      symbol_to_sections_map)
  profiled_sections = _StripSuffixes(
      GetSectionsFromOrderfile(unpatched_orderfile))
  expanded_sections = _ExpandSections(
      profiled_sections, name_to_symbol_infos, offset_to_symbol_infos,
      section_to_symbols_map, symbol_to_sections_map, suffixed)

  with open(output_filename, 'w') as f:
    # Make sure the anchor functions are located in the right place, here and
    # after everything else.
    # See the comment in //base/android/library_loader/anchor_functions.cc.
    #
    # __cxx_global_var_init is one of the largest symbols (~38kB as of May
    # 2018), called extremely early, and not instrumented.
    first_sections = ('dummy_function_start_of_ordered_text',
                      '__cxx_global_var_init')
    for section in first_sections:
      for prefix in _PREFIXES:
        f.write(prefix + section + '\n')

    for section in expanded_sections:
      f.write(section + '\n')

    for prefix in _PREFIXES:
      f.write(prefix + 'dummy_function_end_of_ordered_text\n')

    # The following is needed otherwise Gold only applies a partial sort.
    f.write('.text\n')  # gets methods not in a section, such as assembly
    f.write('.text.*\n')  # gets everything else

    # Since wildcards are not supported by lld, the "end of text" anchor symbol
    # is not emitted, a different mechanism is used instead. See comments in the
    # file above.
    for prefix in _PREFIXES:
      if prefix:
        f.write(prefix + 'dummy_function_at_the_end_of_text\n')
def main():
    parser = optparse.OptionParser(
        usage='usage: %prog [options] <binary> <orderfile>')
    parser.add_option('--target-arch',
                      action='store',
                      dest='arch',
                      choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'],
                      help='The target architecture for the binary.')
    parser.add_option(
        '--threshold',
        action='store',
        dest='threshold',
        default=20,
        help='The maximum allowed number of out-of-order symbols.')
    options, argv = parser.parse_args(sys.argv)
    if not options.arch:
        options.arch = cygprofile_utils.DetectArchitecture()
    if len(argv) != 3:
        parser.print_help()
        return 1
    (binary_filename, orderfile_filename) = argv[1:]

    symbol_extractor.SetArchitecture(options.arch)
    obj_dir = cygprofile_utils.GetObjDir(binary_filename)
    symbol_to_sections_map = cyglog_to_orderfile.ObjectFileProcessor(
        obj_dir).GetSymbolToSectionsMap()
    section_to_symbols_map = cygprofile_utils.InvertMapping(
        symbol_to_sections_map)
    symbols = patch_orderfile.GetSymbolsFromOrderfile(orderfile_filename,
                                                      section_to_symbols_map)
    symbol_infos = symbol_extractor.SymbolInfosFromBinary(binary_filename)
    # Missing symbols is not an error since some of them can be eliminated through
    # inlining.
    (misordered_pairs_count, matched_symbols,
     _) = _CountMisorderedSymbols(symbols, symbol_infos)
    return (misordered_pairs_count > options.threshold) or (matched_symbols
                                                            == 0)
Beispiel #4
0
    def Generate(self):
        """Generates and maybe upload an order."""
        profile_uploaded = False
        orderfile_uploaded = False

        assert (bool(self._options.profile)
                ^ bool(self._options.manual_symbol_offsets))

        if self._options.profile:
            try:
                _UnstashOutputDirectory(self._instrumented_out_dir)
                self._compiler = ClankCompiler(
                    self._instrumented_out_dir, self._step_recorder,
                    self._options.arch, self._options.jobs,
                    self._options.max_load, self._options.use_goma,
                    self._options.goma_dir)
                self._compiler.CompileChromeApk(True)
                self._GenerateAndProcessProfile()
                self._MaybeArchiveOrderfile(
                    self._GetUnpatchedOrderfileFilename())
                profile_uploaded = True
            finally:
                self._DeleteTempFiles()
                _StashOutputDirectory(self._instrumented_out_dir)
        elif self._options.manual_symbol_offsets:
            assert self._options.manual_libname
            assert self._options.manual_objdir
            with file(self._options.manual_symbol_offsets) as f:
                symbol_offsets = [int(x) for x in f.xreadlines()]
            processor = process_profiles.SymbolOffsetProcessor(
                self._options.manual_libname)
            generator = cyglog_to_orderfile.OffsetOrderfileGenerator(
                processor,
                cyglog_to_orderfile.ObjectFileProcessor(
                    self._options.manual_objdir))
            ordered_sections = generator.GetOrderedSections(symbol_offsets)
            if not ordered_sections:  # Either None or empty is a problem.
                raise Exception('Failed to get ordered sections')
            with open(self._GetUnpatchedOrderfileFilename(), 'w') as orderfile:
                orderfile.write('\n'.join(ordered_sections))

        if self._options.patch:
            if self._options.profile:
                self._RemoveBlanks(self._GetUnpatchedOrderfileFilename(),
                                   self._GetPathToOrderfile())
            try:
                _UnstashOutputDirectory(self._uninstrumented_out_dir)
                self._compiler = ClankCompiler(
                    self._uninstrumented_out_dir, self._step_recorder,
                    self._options.arch, self._options.jobs,
                    self._options.max_load, self._options.use_goma,
                    self._options.goma_dir)
                self._compiler.CompileLibchrome(False)
                self._PatchOrderfile()
                # Because identical code folding is a bit different with and without
                # the orderfile build, we need to re-patch the orderfile with code
                # folding as close to the final version as possible.
                self._compiler.CompileLibchrome(False, force_relink=True)
                self._PatchOrderfile()
                self._compiler.CompileLibchrome(False, force_relink=True)
                self._VerifySymbolOrder()
                self._MaybeArchiveOrderfile(self._GetPathToOrderfile())
            finally:
                _StashOutputDirectory(self._uninstrumented_out_dir)
            orderfile_uploaded = True

        if (self._options.buildbot and self._options.netrc
                and not self._step_recorder.ErrorRecorded()):
            unpatched_orderfile_filename = (
                self._GetUnpatchedOrderfileFilename()
                if profile_uploaded else None)
            orderfile_filename = (self._GetPathToOrderfile()
                                  if orderfile_uploaded else None)
            self._orderfile_updater.CommitFileHashes(
                unpatched_orderfile_filename, orderfile_filename)

        self._step_recorder.EndStep()
        return not self._step_recorder.ErrorRecorded()
Beispiel #5
0
  def Generate(self):
    """Generates and maybe upload an order."""
    assert (bool(self._options.profile) ^
            bool(self._options.manual_symbol_offsets))
    if self._options.system_health_orderfile and not self._options.profile:
      raise AssertionError('--system_health_orderfile must be not be used '
                           'with --skip-profile')
    if (self._options.manual_symbol_offsets and
        not self._options.system_health_orderfile):
      raise AssertionError('--manual-symbol-offsets must be used with '
                           '--system_health_orderfile.')

    if self._options.profile:
      try:
        _UnstashOutputDirectory(self._instrumented_out_dir)
        self._compiler = ClankCompiler(
            self._instrumented_out_dir, self._step_recorder, self._options.arch,
            self._options.use_goma, self._options.goma_dir,
            self._options.system_health_orderfile, self._monochrome,
            self._options.public, self._GetPathToOrderfile())
        if not self._options.pregenerated_profiles:
          # If there are pregenerated profiles, the instrumented build should
          # not be changed to avoid invalidating the pregenerated profile
          # offsets.
          self._compiler.CompileChromeApk(instrumented=True,
                                          use_call_graph=
                                          self._options.use_call_graph)
        self._GenerateAndProcessProfile()
        self._MaybeArchiveOrderfile(self._GetUnpatchedOrderfileFilename())
      finally:
        _StashOutputDirectory(self._instrumented_out_dir)
    elif self._options.manual_symbol_offsets:
      assert self._options.manual_libname
      assert self._options.manual_objdir
      with file(self._options.manual_symbol_offsets) as f:
        symbol_offsets = [int(x) for x in f.xreadlines()]
      processor = process_profiles.SymbolOffsetProcessor(
          self._compiler.manual_libname)
      generator = cyglog_to_orderfile.OffsetOrderfileGenerator(
          processor, cyglog_to_orderfile.ObjectFileProcessor(
              self._options.manual_objdir))
      ordered_sections = generator.GetOrderedSections(symbol_offsets)
      if not ordered_sections:  # Either None or empty is a problem.
        raise Exception('Failed to get ordered sections')
      with open(self._GetUnpatchedOrderfileFilename(), 'w') as orderfile:
        orderfile.write('\n'.join(ordered_sections))

    if self._options.patch:
      if self._options.profile:
        self._RemoveBlanks(self._GetUnpatchedOrderfileFilename(),
                           self._GetPathToOrderfile())
      try:
        _UnstashOutputDirectory(self._uninstrumented_out_dir)
        self._compiler = ClankCompiler(
            self._uninstrumented_out_dir, self._step_recorder,
            self._options.arch, self._options.use_goma, self._options.goma_dir,
            self._options.system_health_orderfile, self._monochrome,
            self._options.public, self._GetPathToOrderfile())

        self._compiler.CompileLibchrome(instrumented=False,
                                        use_call_graph=False)
        self._PatchOrderfile()
        # Because identical code folding is a bit different with and without
        # the orderfile build, we need to re-patch the orderfile with code
        # folding as close to the final version as possible.
        self._compiler.CompileLibchrome(instrumented=False,
                                        use_call_graph=False, force_relink=True)
        self._PatchOrderfile()
        self._compiler.CompileLibchrome(instrumented=False,
                                        use_call_graph=False, force_relink=True)
        self._VerifySymbolOrder()
        self._MaybeArchiveOrderfile(self._GetPathToOrderfile())
      finally:
        _StashOutputDirectory(self._uninstrumented_out_dir)

    if self._options.benchmark:
      self._output_data['orderfile_benchmark_results'] = self.RunBenchmark(
          self._uninstrumented_out_dir)
      self._output_data['no_orderfile_benchmark_results'] = self.RunBenchmark(
          self._no_orderfile_out_dir, no_orderfile=True)

    if self._options.buildbot:
      self._orderfile_updater._GitStash()
    self._step_recorder.EndStep()
    return not self._step_recorder.ErrorRecorded()