def _OutputOrderfile(offsets, offset_to_symbol_infos, symbol_to_section_map, output_file): """Outputs the orderfile to output_file. Args: offsets: Iterable of offsets to match to section names offset_to_symbol_infos: {offset: [SymbolInfo]} symbol_to_section_map: {name: section} output_file: file-like object to write the results to """ success = True unknown_symbol_warnings = cygprofile_utils.WarningCollector(300) symbol_not_found_warnings = cygprofile_utils.WarningCollector(300) output_sections = set() for offset in offsets: try: symbol_infos = _FindSymbolInfosAtOffset(offset_to_symbol_infos, offset) for symbol_info in symbol_infos: if symbol_info.name in symbol_to_section_map: section = symbol_to_section_map[symbol_info.name] if not section in output_sections: output_file.write(section + '\n') output_sections.add(section) else: unknown_symbol_warnings.Write( 'No known section for symbol ' + symbol_info.name) except SymbolNotFoundException: symbol_not_found_warnings.Write( 'Did not find function in binary. offset: ' + hex(offset)) success = False unknown_symbol_warnings.WriteEnd('no known section for symbol.') symbol_not_found_warnings.WriteEnd('symbol not found in the binary.') return success
def CreateNameToSymbolInfo(symbol_infos): """Create a dict {name: symbol_info, ...}. Args: symbol_infos: iterable of SymbolInfo instances Returns: a dict {name: symbol_info, ...} If a symbol name corresponds to more than one symbol_info, the symbol_info with the lowest offset is chosen. """ # TODO(lizeb,pasko): move the functionality in this method into # check_orderfile. symbol_infos_by_name = {} warnings = cygprofile_utils.WarningCollector(_MAX_WARNINGS_TO_PRINT) for infos in GroupSymbolInfosByName(symbol_infos).itervalues(): first_symbol_info = min(infos, key=lambda x:x.offset) symbol_infos_by_name[first_symbol_info.name] = first_symbol_info if len(infos) > 1: warnings.Write('Symbol %s appears at %d offsets: %s' % (first_symbol_info.name, len(infos), ','.join([hex(x.offset) for x in infos]))) warnings.WriteEnd('symbols at multiple offsets.') return symbol_infos_by_name
def _GetSymbolToSectionMapFromObjectFiles(obj_dir): """ Creates a mapping from symbol to linker section name by scanning all the object files. """ object_files = _GetObjectFileNames(obj_dir) symbol_to_section_map = {} symbol_warnings = cygprofile_utils.WarningCollector(300) symbol_infos = _AllSymbolInfos(object_files) for symbol_info in symbol_infos: symbol = symbol_info.name if symbol.startswith('.LTHUNK'): continue section = symbol_info.section if ((symbol in symbol_to_section_map) and (symbol_to_section_map[symbol] != symbol_info.section)): symbol_warnings.Write('Symbol ' + symbol + ' in conflicting sections ' + section + ' and ' + symbol_to_section_map[symbol]) elif not section.startswith('.text'): symbol_warnings.Write('Symbol ' + symbol + ' in incorrect section ' + section) else: symbol_to_section_map[symbol] = section symbol_warnings.WriteEnd('bad sections') return symbol_to_section_map
def GetOrderedSections(self, offsets): """Get ordered list of sections corresponding to offsets. Args: offsets ([int]) dump offsets, from same build as parameters to __init__. Returns: [str] ordered list of sections suitable for use as an orderfile, or None if failure. """ symbol_to_sections = self._obj_processor.GetSymbolToSectionsMap() if not symbol_to_sections: logging.error('No symbol section names found') return None unknown_symbol_warnings = cygprofile_utils.WarningCollector(300) symbol_not_found_errors = cygprofile_utils.WarningCollector( 300, level=logging.ERROR) seen_sections = set() ordered_sections = [] success = True for offset in offsets: try: symbol_infos = self._SymbolsAtOffset(offset) for symbol_info in symbol_infos: if symbol_info.name in symbol_to_sections: sections = symbol_to_sections[symbol_info.name] for section in sections: if not section in seen_sections: ordered_sections.append(section) seen_sections.add(section) else: unknown_symbol_warnings.Write( 'No known section for symbol ' + symbol_info.name) except _SymbolNotFoundException: symbol_not_found_errors.Write( 'Did not find function in binary. offset: ' + hex(offset)) success = False unknown_symbol_warnings.WriteEnd('no known section for symbol.') symbol_not_found_errors.WriteEnd('symbol not found in the binary.') if not success: return None return ordered_sections
def GetSymbolToSectionsMapFromObjectFiles(obj_dir): """Scans object files to create a {symbol: linker section(s)} map. Args: obj_dir: The root of the output object file directory, which will be scanned for .o files to form the mapping. Returns: A map {symbol_name: [section_name1, section_name2...]} """ object_files = GetObjectFileNames(obj_dir) symbol_to_sections_map = {} symbol_warnings = cygprofile_utils.WarningCollector(300) symbol_infos = _AllSymbolInfos(object_files) for symbol_info in symbol_infos: symbol = symbol_info.name if symbol.startswith('.LTHUNK'): continue section = symbol_info.section if ((symbol in symbol_to_sections_map) and (symbol_info.section not in symbol_to_sections_map[symbol])): symbol_to_sections_map[symbol].append(section) if not _SameCtorOrDtorNames( symbol, symbol_to_sections_map[symbol][0].lstrip('.text.')): symbol_warnings.Write( 'Symbol ' + symbol + ' unexpectedly in more than one section: ' + ', '.join(symbol_to_sections_map[symbol])) elif not section.startswith('.text.'): # Assembly functions have section ".text". These are all grouped together # near the end of the orderfile via an explicit ".text" entry. if section != '.text': symbol_warnings.Write('Symbol ' + symbol + ' in incorrect section ' + section) else: # In most cases we expect just one item in this list, and maybe 4 or so in # the worst case. symbol_to_sections_map[symbol] = [section] symbol_warnings.WriteEnd('bad sections') return symbol_to_sections_map
def GetSymbolToSectionsMap(self): """Scans object files to find symbol section names. Returns: {symbol: linker section(s)} """ if self._symbol_to_sections_map is not None: return self._symbol_to_sections_map symbol_infos = self._GetAllSymbolInfos() self._symbol_to_sections_map = {} symbol_warnings = cygprofile_utils.WarningCollector(300) for symbol_info in symbol_infos: symbol = symbol_info.name if symbol.startswith('.LTHUNK'): continue section = symbol_info.section if ((symbol in self._symbol_to_sections_map) and (symbol_info.section not in self._symbol_to_sections_map[symbol])): self._symbol_to_sections_map[symbol].append(section) if not self._SameCtorOrDtorNames( symbol, self._symbol_to_sections_map[symbol][0].lstrip( '.text.')): symbol_warnings.Write( 'Symbol ' + symbol + ' unexpectedly in more than one section: ' + ', '.join(self._symbol_to_sections_map[symbol])) elif not section.startswith('.text.'): # Assembly functions have section ".text". These are all grouped # together near the end of the orderfile via an explicit ".text" entry. if section != '.text': symbol_warnings.Write('Symbol ' + symbol + ' in incorrect section ' + section) else: # In most cases we expect just one item in this list, and maybe 4 or so # in the worst case. self._symbol_to_sections_map[symbol] = [section] symbol_warnings.WriteEnd('bad sections') return self._symbol_to_sections_map