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())
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)
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()
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()