def get_macros_expansions(self, files=None, macros_names=None): """Get dictionary with macros expansions (C only). DEPRECATED: use get_expansions() instead. Args: files: A list of files to narrow down returned dictionary macros_names: A list of macros names to find and return """ exps = self.Macros.load_expansions(files) expansions = nested_dict() # Map new format of macros to the old one for exp_file, macro, _, _, _, args in traverse(exps, 6): if expansions[exp_file][macro]["args"]: expansions[exp_file][macro]["args"].extend(args) else: expansions[exp_file][macro]["args"] = args if macros_names: filtered_expansions = nested_dict() for file, macros in traverse(expansions, 2): if macros in macros_names: filtered_expansions[file][macros] = expansions[file][ macros] return filtered_expansions return expansions
def get_macros_definitions(self, files=None, macros_names=None): """Get dictionary with macros definitions (C only). DEPRECATED: use get_macros() instead. Args: files: A list of files to narrow down returned dictionary macros_names: A list of macros names to find and return """ macros = self.Macros.load_macros(files) definitions = nested_dict() # Map new format of macros to the old one for file, macro, line in traverse(macros, 3): if definitions[file][macro]: definitions[file][macro].append(line) else: definitions[file][macro] = [line] # Filter macro definitions by names if macros_names: filtered_definitions = nested_dict() for file, macros in traverse(definitions, 2): if macros in macros_names: filtered_definitions[file][macros] = definitions[file][ macros] return filtered_definitions return definitions
def __process_functions_usages(self): for context_file, context_func, func, line in self.extensions[ "Info"].iter_functions_usages(): if self.is_builtin.match(func): continue if func not in self.funcs: self._error( "Use of function without definition: {}".format(func)) continue # For each function call there can be many definitions with the same name, defined in different files. # possible_files is a list of them. possible_files = tuple(f for f in self.funcs[func] if f != "unknown") if len(possible_files) == 0: self._error("No possible definitions for use: {}".format(func)) continue # Assign priority number for each possible definition. Examples: # 3 means that definition is located in the same file as the call # 2 - in the same translation unit # 1 - in the object file that is linked with the object file that contains the call # 0 - definition is not found index = 3 for files in ((f for f in possible_files if f == context_file), (f for f in possible_files if self._t_unit_is_common(f, context_file)), (f for f in possible_files if self._files_are_linked(f, context_file)), ['unknown']): matched_files = tuple(files) if matched_files: break index -= 1 else: raise RuntimeError("We do not expect any other file class") if len(matched_files) > 1: self._error("Multiple matches for use: {} call in {}".format( func, context_func)) for possible_file in matched_files: if func not in self.used_in[possible_file]: self.used_in[possible_file][func] = { "used_in_file": nested_dict(), "used_in_func": nested_dict() } if context_func == "NULL": self.used_in[possible_file][func]["used_in_file"][ context_file][line] = index else: self.used_in[possible_file][func]["used_in_func"][ context_file][context_func][line] = index if possible_file == "unknown": self._error("Can't match definition for use: {} {}".format( func, context_file))
def __init__(self, work_dir, conf=None): super().__init__(work_dir, conf) self.macros = nested_dict() self.macros_folder = "macros" self.exps = nested_dict() self.exps_folder = "expansions"
def __init__(self, work_dir, conf=None): super().__init__(work_dir, conf) self.src_graph = dict() self.funcs = nested_dict() self.funcs_file = "functions.json" self.funcs_by_file = nested_dict() self.funcs_by_file_file = "functions_by_file.json" self.funcs_by_file_folder = "functions_by_file"
def __get_raw_locations(self): raw_locations = nested_dict() raw_locations = self.__get_raw_func_locations(raw_locations) raw_locations = self.__get_raw_macro_locations(raw_locations) return raw_locations
def __gen_ref_from_macro(self, locations): for def_file, macros in self.extensions["Macros"].yield_macros(): if def_file == "unknown" or "def_macro" not in locations[def_file]: continue ref_from = nested_dict() for macro, loc_list in traverse(locations[def_file]["def_macro"], 2): for loc_el in loc_list: def_line = str(loc_el[0]) for exp_file in macros[def_file][macro][def_line]: exp_lines = [ int(l) for l in macros[def_file][macro][def_line] [exp_file] ] val = (loc_el, (exp_file, exp_lines)) if ref_from[def_file]["expand"]: ref_from[def_file]["expand"].append(val) else: ref_from[def_file]["expand"] = [val] self.__dump_ref_from(ref_from)
def __gen_ref_from_func(self, locations): for file, callgraph in self.extensions["Callgraph"].yield_callgraph(): ref_from = nested_dict() for func in self.funcs[file]: context_locs = self.__get_context_locs(file, func, callgraph) if file != "unknown" and func in locations[file]["def_func"]: loc_list = locations[file]["def_func"][func] for context_file, lines in context_locs: for loc_el in loc_list: val = (loc_el, (context_file, lines)) if ref_from[file]["call"]: ref_from[file]["call"].append(val) else: ref_from[file]["call"] = [val] for decl_file in self.funcs[file][func]["declarations"]: if func in locations[decl_file]["decl_func"]: loc_list = locations[decl_file]["decl_func"][func] for context_file, lines in context_locs: for loc_el in loc_list: val = (loc_el, (context_file, lines)) if ref_from[decl_file]["call"]: ref_from[decl_file]["call"].append(val) else: ref_from[decl_file]["call"] = [val] self.__dump_ref_from(ref_from)
def __gen_ref_to_macro(self, locations): for exp_file, expansions in self.extensions["Macros"].yield_expansions( ): if exp_file == "unknown" or "expand" not in locations[exp_file]: continue ref_to = nested_dict() for macro, loc_list in traverse(locations[exp_file]["expand"], 2): for loc_el in loc_list: exp_line = str(loc_el[0]) for def_file, def_line in traverse( expansions[exp_file][macro][exp_line], 2): if def_file == "unknown": continue val = (loc_el, (def_file, int(def_line))) if ref_to[exp_file]["def_macro"]: ref_to[exp_file]["def_macro"].append(val) else: ref_to[exp_file]["def_macro"] = [val] self.__dump_ref_to(ref_to)
def __parse_file(self, file, raw_locations, ignore_errors=False, encoding="utf8"): storage_file = self.extensions["Storage"].get_storage_path(file) if not os.path.exists(storage_file): # There may be some header files from CIF that are not in the storage if os.path.exists(file): self.extensions["Storage"].add_file(file) else: return None locations = nested_dict() sorted_locs = sorted(raw_locations[file], key=lambda x: int(x[0])) sorted_pos = 0 try: if ignore_errors: fp = codecs.open(storage_file, "r", encoding=encoding, errors="ignore") else: fp = open(storage_file, "r", encoding=encoding) for i, s in enumerate(fp): if sorted_pos >= len(sorted_locs): break while (sorted_pos < len(sorted_locs) and int(sorted_locs[sorted_pos][0]) <= i + 1): if i == int(sorted_locs[sorted_pos][0]) - 1: line = int(sorted_locs[sorted_pos][0]) name = sorted_locs[sorted_pos][1] ctype = sorted_locs[sorted_pos][2] for lowest_index in self.__find_all(s, name): val = (line, lowest_index, lowest_index + len(name)) if name in locations[ctype]: locations[ctype][name].append(val) else: locations[ctype][name] = [val] # Only one macro definition can be on a single line if ctype == "def_macro": break # TODO: there may be a function call inside macro expansion sorted_pos += 1 return locations except UnicodeDecodeError: return self.__parse_file(file, raw_locations, ignore_errors=True) finally: fp.close()
def __init__(self, work_dir, conf=None): super().__init__(work_dir, conf) self.src_graph = dict() self.funcs = dict() self.err_log = os.path.join(self.work_dir, "err.log") self.callgraph = nested_dict() self.callgraph_folder = "callgraph" self.calls_by_ptr = nested_dict() self.calls_by_ptr_file = "calls_by_ptr.json" self.used_in = nested_dict() self.used_in_file = "used_in.json" self.is_builtin = re.compile(r'(__builtin)|(__compiletime)')
def __gen_ref_to_func(self, locations): for context_file, callgraph in self.extensions[ "Callgraph"].yield_callgraph(): calls = set() for context_func, _, file in traverse(callgraph[context_file], 3, {2: "calls"}): if file not in self.funcs: self._error("Can't find file: {!r}".format(file)) continue for func in callgraph[context_file][context_func]["calls"][ file]: if func not in locations[context_file]["call"]: # Probably because of macro expansion continue if func not in self.funcs[file]: self._error("Can't find function: {!r} {!r}".format( func, file)) continue calls.add((file, func)) ref_to = nested_dict() for file, func in calls: loc_list = locations[context_file]["call"][func] if self.funcs[file][func]["line"]: def_line = int(self.funcs[file][func]["line"]) for loc_el in loc_list: val = (loc_el, (file, def_line)) if ref_to[context_file]["def_func"]: ref_to[context_file]["def_func"].append(val) else: ref_to[context_file]["def_func"] = [val] for decl_file in self.funcs[file][func]["declarations"]: decl_line = int(self.funcs[file][func]["declarations"] [decl_file]["line"]) for loc_el in loc_list: val = (loc_el, (decl_file, decl_line)) if ref_to[context_file]["decl_func"]: ref_to[context_file]["decl_func"].append(val) else: ref_to[context_file]["decl_func"] = [val] self.__dump_ref_to(ref_to)
def __process_macros_definitions(self): for file, macro, line in self.extensions[ "Info"].iter_macros_definitions(): self.macros[file][macro][line] = nested_dict()