def main(): global syms, scanned_files syms, scanned_files = analyze_source.read_source_and_syms() time_start = time.time() update_function_scope() time_end = time.time() debug_print("Time taken: %s" % (time_end - time_start))
def read_syms(): syms = {} debug_print("Reading syms...") import os objdump_path = "./tools/binutils/bin/arm-none-eabi-objdump" if 'win' in os.name: output = subprocess.check_output( [objdump_path + ".exe", "-t", "bn6f.elf"]) else: output = subprocess.check_output([objdump_path, "-t", "bn6f.elf"]) lines = output.splitlines()[4:] for line in lines: try: sym_tuple = sym_line_regex.findall(line.decode("utf-8"))[0] except IndexError: break sym_list = list(sym_tuple) sym_list[0] = int(sym_list[0], 16) # symbol name syms[sym_tuple[5]] = SymInfo(*sym_list) debug_print("Done reading syms!") return syms
def update_function_scope(): branch_opcodes = set( ("beq", "bne", "bcs", "bcc", "bmi", "bpl", "bvs", "bvc", "bhi", "bls", "bge", "blt", "bgt", "ble", "b", "bl")) functions = {} for sym in syms.values(): if sym.type == "F": functions[sym.name] = sym.filename for src_file in scanned_files.values(): if src_file.filename.startswith("data/dat38"): continue src_file.line_num = 0 debug_print(src_file.filename) for line in src_file: if line.isspace() or line == "": continue words = parser.for_loop_parse_word_directives(src_file) if len(words) == 0: # check for opcode line = line.strip() opcode_parts = line.split(None, 1) if len(opcode_parts) > 1 and opcode_parts[0] in branch_opcodes: if opcode_parts[1].endswith("+1"): opcode_parts[1] = opcode_parts[:-2] if opcode_parts[ 1] in functions and src_file.filename != syms[ opcode_parts[1]].filename: change_function_to_thumb_func_start( syms[opcode_parts[1]]) del functions[opcode_parts[1]] else: # test each word to see if it's a function # if it is, increment its counter for word in words: if word.endswith("+1"): word = word[:-2] if word in functions and src_file.filename != syms[ word].filename: change_function_to_thumb_func_start(syms[word]) del functions[word] # functions that are confirmed local for function in functions.keys(): change_function_to_thumb_local_start(syms[function]) if os.path.exists("temp/"): shutil.rmtree("temp/") os.makedirs("temp/") for filename, src_file in scanned_files.items(): os.makedirs("temp/" + os.path.dirname(filename), exist_ok=True) with open("temp/" + filename, "w+") as f: f.writelines(line + "\n" for line in src_file.commented_lines)
def benchmark_list_iterator(scanned_files): list_iterator_start_time = time.time() for src_file in scanned_files.values(): src_file.line_num = 0 output = "" for line in src_file._uncommented_lines: output += line list_iterator_total_time = time.time() - list_iterator_start_time debug_print("list_iterator_total_time: %s" % list_iterator_total_time)
def benchmark_src_file_iterator(scanned_files): src_file_iterator_start_time = time.time() for src_file in scanned_files.values(): src_file.line_num = 0 output = "" for line in src_file: output += line src_file_iterator_total_time = time.time() - src_file_iterator_start_time debug_print("src_file_iterator_total_time: %s" % src_file_iterator_total_time)
def count_functions(syms, scanned_files): branch_opcodes = set( ("beq", "bne", "bcs", "bcc", "bmi", "bpl", "bvs", "bvc", "bhi", "bls", "bge", "blt", "bgt", "ble", "b", "bl")) function_counts = {} for sym in syms.values(): if sym.type == "F": function_counts[sym.name] = 0 for src_file in scanned_files.values(): if src_file.filename.startswith("data/dat38"): continue src_file.line_num = 0 debug_print(src_file.filename) for line in src_file: if line.isspace() or line == "": continue words = parser.for_loop_parse_word_directives(src_file) if len(words) == 0: # check for opcode line = line.strip() opcode_parts = line.split(None, 1) if len(opcode_parts) > 1 and opcode_parts[0] in branch_opcodes: if opcode_parts[1].endswith("+1"): opcode_parts[1] = opcode_parts[:-2] if opcode_parts[1] in function_counts: function_counts[opcode_parts[1]] += 1 else: # test each word to see if it's a function # if it is, increment its counter for word in words: if word.endswith("+1"): old_word = word word = word[:-2] if word in function_counts: function_counts[word] += 1 sorted_function_counts = sorted(function_counts.items(), key=lambda kv: kv[1], reverse=True) output = "" for function_pair in sorted_function_counts: function_sym = syms[function_pair[0]] output += "{:07x} <{}:{}> {}: {}\n".format(function_sym.value, function_sym.filename, function_sym.line_num + 1, function_sym.name, function_pair[1]) with open("function_counts.txt", "w+") as f: f.write(output)
def recursive_scan_includes(filepath, scanned_files, syms=None, callbacks=None): global recursion_depth debug_print("recursion depth: %s | file: %s" % (recursion_depth, filepath)) recursion_depth += 1 in_block_comment = False with open(filepath, "r") as f: scanned_files[filepath] = SrcFile(filepath) for line_num, line in enumerate(f): include_file_list = re.findall(r"\t\.include \"([^\"]+)\"", line) if len(include_file_list) > 1: raise RuntimeError("More than one group found!") elif len(include_file_list) == 1: include_given_pathname = include_file_list[0] include_real_pathname = include_given_pathname if include_given_pathname.endswith(".inc"): if pathlib.Path(include_given_pathname).is_file(): pass # already defined as default elif pathlib.Path("include/" + include_given_pathname).is_file(): include_real_pathname = "include/" + include_given_pathname else: raise RuntimeError( "Path specified by \"%s\" not found!" % include_given_pathname) if include_real_pathname not in scanned_files: try: recursive_scan_includes(include_real_pathname, scanned_files, syms, callbacks) except IOError: raise line = line.rstrip("\r\n") uncommented_line = "" in_line_comment = False iter_line = IterStr(line) # faster to do this naive check for most cases because "in" is native if not in_block_comment and "/*" not in line: slash_line_comment_index = line.find("//") * -1 at_line_comment_index = line.find("@") * -1 if at_line_comment_index == 1 or slash_line_comment_index == 1: line_comment_index = min(slash_line_comment_index, at_line_comment_index) * -1 else: line_comment_index = max(slash_line_comment_index, at_line_comment_index) * -1 if line_comment_index == -1: uncommented_line = line else: uncommented_line = line[:line_comment_index] + " " * ( len(line) - line_comment_index - 1) else: for char in iter_line: if in_block_comment: uncommented_line += " " if char == "*": try: char = iter_line.next() except StopIteration: break uncommented_line += " " if char == "/": in_block_comment = False elif char == "@": uncommented_line += " " * (len(line) - iter_line.index - 1) break elif char == "/": try: char = iter_line.next() except StopIteration: break if char == "/": uncommented_line += " " + " " * ( len(line) - iter_line.index - 1) break elif char == "*": uncommented_line += " " in_block_comment = True else: uncommented_line += char if syms is not None: label_name = parser.check_and_parse_colon_label( uncommented_line) if label_name is not None: syms[label_name].filename = filepath syms[label_name].line_num = line_num if callbacks is not None: for callback in callbacks: callback(line, uncommented_line) scanned_files[filepath].append_commented_and_uncommented_lines( line, uncommented_line) recursion_depth -= 1
ap.add_argument("-m", "--make", dest="make", action="store_true") ap.add_argument("-p", "--path", dest="input_path") args = ap.parse_args() if args.input_path is None and os.path.basename( os.getcwd()) == "analyze_source": os.chdir("../..") elif args.input_path is not None: os.chdir(args.input_path) if args.make: syms = make_and_read_syms() else: syms = read_syms() debug_print("Size: %s" % sys.getsizeof(syms)) sym_dump_output = "" cfg_output = "" highest_sym_value = 0 sorted_syms = sorted(syms.items(), key=lambda kv: kv[1].value) for sym, sym_info in sorted_syms: sym_dump_output += "{}: value=0x{:x}, scope=\"{}\", debug=\"{}\", type=\"{}\", section=\"{}\"\n".format( sym, sym_info.value, sym_info.scope, sym_info.debug, sym_info.type, sym_info.section) if sym_info.type == "F" and sym_info.value >= 0x8000000: cfg_output += "{} 0x{:x} {}\n".format("thumb_func", sym_info.value, sym) with open("bn6f_syms.dump", "w+") as f: f.write(sym_dump_output)