blob: 663377ad4ee7690fb3c6fa1ec5b18464eb420534 [file] [log] [blame]
#!/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()