def _determine_units(self, program): """ Create a module from all files compiled in .ko loadable module and files from directories compiled in modules build-in files also separate in units. :param program: Program object. """ for desc in program.clade.get_all_cmds_by_type("LD"): identifier = desc['id'] # This shouldn't happen ever, but let's fail otherwise. if len(desc['out']) != 1: self.logger.warning( "LD commands with several out files are not supported, skip commands: {!r}" .format(identifier)) continue out = desc['out'][0] if out.endswith('.ko') or out.endswith('built-in.o'): rel_object_path = make_relative_path(self.source_paths, out) name = rel_object_path fragment = program.create_fragment_from_linker_cmds( identifier, desc, name, out.endswith('built-in.o') and self._separate_nested) if (not self._max_size or fragment.size <= self._max_size ) and len(fragment.files) != 0: program.add_fragment(fragment) else: self.logger.debug( 'Fragment {!r} is rejected since it exceeds maximum size or does not contain ' 'files {!r}'.format(fragment.name, fragment.size))
def __prepare_data_files(self, grps, tactic, fragmentation_set): """ Prepare data files that describe program fragments content. :param grps: Dictionary with program fragments with dependencies. :param tactic: Name of the tactic. :param grps: Name of the fragmentation set. :return: Attributes and dict a list of data files. """ data = dict() for name, main_and_frgs in grps.items(): main, frags = main_and_frgs data[name] = { "files": [make_relative_path(self.source_paths, l.name) for f in frags for l in f.files], "size": str(sum(int(f.size) for f in frags)) } with open('aggregations description.json', 'w', encoding='utf-8') as fp: ujson.dump(data, fp, sort_keys=True, indent=4, ensure_ascii=False, escape_forward_slashes=False) return [{ 'name': 'Program fragmentation', 'value': [ { 'name': 'tactic', 'value': tactic }, { 'name': 'set', 'value': fragmentation_set } ] }], 'aggregations description.json'
def _determine_units(self, program): """ Find all files that has \w+_main function and add dependencies files except that ones that stored in libbb dir. All files from the libbb directory add to the specific unit with the libbb name. :param program: Program object. """ main_func = re.compile("\\w+main") libbb = set() applets = dict() for file in program.files: rel_path = make_relative_path(self.source_paths, str(file)) if os.path.commonpath(['libbb', rel_path]): libbb.add(file) else: for func in file.export_functions: if main_func.match(func): path, name = os.path.split(rel_path) name = os.path.splitext(name)[0] applets[name] = {file} if self._incorporate_libbb: dfiles = program.collect_dependencies({file}) else: dfiles = program.collect_dependencies( {file}, filter_func=lambda x: not os.path.commonpath([ 'libbb', make_relative_path(self.source_paths, x. name) ])) applets[name].update(dfiles) # Create fragments for found applets and libbb for name, files in applets.items(): program.create_fragment(name, files, add=True) for file in files: if file.name not in self._match_files: self._match_files[file.name] = 0 else: self._match_files[file.name] += 1 program.create_fragment('libbb', libbb, add=True) self.logger.info('Found {} applets: {}'.format(len(applets), ', '.join(applets)))
def _determine_units(self, program): """ Consider all program source files as independent program fragments. :param program: Program object. """ for file in program.files: name = make_relative_path(self.source_paths, file.name) program.create_fragment(name, {file}, add=True)
def __describe_program_fragment(self, program, name, grp): """ Create the JSON file for the given program fragment with dependencies. :param program: Program object. :param name: Name of the fragment. :param grp: Set of fragments with dependencies. :return: The name of the created file. """ # Determine fragment name main_fragment, fragments = grp self.logger.info('Generate fragment description {!r}'.format(name)) pf_desc = { 'id': name, 'fragment': name, 'targets': sorted([str(f) for f in main_fragment.target_files]), 'grps': list(), 'deps': dict(), 'size': str(sum((int(f.size) for f in fragments))) } for frag in fragments: fragment_description = { 'id': frag.name, 'Extra CCs': [ {"CC": [file.cmd_id, file.cmd_type], "in file": str(file)} for file in frag.files ], 'files': sorted(make_relative_path(self.source_paths, str(f)) for f in frag.files), 'abs files': sorted(str(f) for f in frag.files) } pf_desc['grps'].append(fragment_description) pf_desc['deps'][frag.name] = [succ.name for succ in program.get_fragment_successors(frag) if succ in fragments] self.logger.debug('Program fragment dependencies are {}'.format(pf_desc['deps'])) pf_desc_file = os.path.join(self.pf_dir, pf_desc['fragment'] + '.json') if os.path.isfile(pf_desc_file): raise FileExistsError('Program fragment description file {!r} already exists'.format(pf_desc_file)) self.logger.debug('Dump program fragment description {!r} to file {!r}'.format(pf_desc['fragment'], pf_desc_file)) dir_path = os.path.dirname(pf_desc_file).encode('utf-8') if dir_path: os.makedirs(dir_path, exist_ok=True) with open(pf_desc_file, 'w', encoding='utf-8') as fp: ujson.dump(pf_desc, fp, sort_keys=True, indent=4, ensure_ascii=False, escape_forward_slashes=False) return pf_desc_file
def __draw_fragment(self, fragment): """ Print a graph with files and dependencies between them for a fragment. :param fragment: Fragment object. """ g = Digraph(graph_attr={'rankdir': 'LR'}, node_attr={'shape': 'rectangle'}) for file in fragment.files: g.node(file.name, make_relative_path(self.source_paths, file.name) + (' (target)' if fragment.target else '')) for file in fragment.files: for suc in file.successors: if suc in fragment.files: g.edge(fragment.name, suc.name) if not os.path.exists('fragments'): os.makedirs('fragments') g.render(os.path.join('fragments', fragment.name))