#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Copyright (C) 2017-2020 The Project X-Ray Authors. # # Use of this source code is governed by a ISC-style # license that can be found in the LICENSE file or at # https://opensource.org/licenses/ISC # # SPDX-License-Identifier: ISC """ This tool allows to view segbits using a 2D frame vs. bit plot. It can read either mask.db files or segbits.db files. Multiple files can be read at once allowing to identify where a bit comes from. When a single file is read, a bit is marked as "O". When multiple files are read, a bit is denoted with a letter "A", "B" and so on depending on index of file that it belongs to. Duplicate bits (present in more than one files) are marked with "#" """ import sys import argparse import re from prjxray.util import OpenSafeFile # ============================================================================= def load_just_bits(file_name): """ Read bits from a .db or .rdb file. Ignores tags and bit values. """ with OpenSafeFile(file_name, "r") as fp: lines = fp.readlines() bits = set() for line in lines: for word in line.split(" "): match = re.match("^(!?)([0-9]+)_([0-9]+)$", word) if match is not None: frm = int(match.group(2)) bit = int(match.group(3)) bits.add(( frm, bit, )) return bits # ============================================================================= def main(): # Colors for TTY if sys.stdout.isatty(): bit_colors = [ "\033[39m", "\033[91m", "\033[92m", "\033[93m", "\033[94m", "\033[95m", "\033[96m", "\033[31m", "\033[32m", "\033[33m", "\033[34m", "\033[35m", "\033[36m", ] colors = { "NONE": "\033[0m", "DUPLICATE": "\033[101;97m", } # Colors for pipe else: bit_colors = [""] colors = { "NONE": "", "DUPLICATE": "", } # ......................................................................... parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("files", nargs="*", type=str, help="Input files") args = parser.parse_args() # Load bits all_bits = [] for i, f in enumerate(args.files): bits = load_just_bits(f) all_bits.append(bits) cstr = bit_colors[i % len(bit_colors)] bstr = "O" if len(args.files) == 1 else chr(65 + i) print(cstr + bstr + colors["NONE"] + ": %s #%d" % (f, len(bits))) print("") max_frames = max([bit[0] for bits in all_bits for bit in bits]) + 1 max_bits = max([bit[1] for bits in all_bits for bit in bits]) + 1 # Header for r in range(3): line = " " * 3 for c in range(max_bits): bstr = "%03d" % c line += bstr[r] print(line) print("") # Display bits for r in range(max_frames): line = "%2d " % r for c in range(max_bits): got_bit = False bit_str = colors["NONE"] + "-" for i, bits in enumerate(all_bits): cstr = bit_colors[i % len(bit_colors)] bstr = "O" if len(args.files) == 1 else chr(65 + i) if (r, c) in bits: if not got_bit: bit_str = cstr + bstr else: bit_str = colors["DUPLICATE"] + "#" + colors["NONE"] got_bit = True line += bit_str line += colors["NONE"] print(line) # ============================================================================= if __name__ == "__main__": main()