forked from Imagelibrary/littlefs
I mean, why not. dbgblock.py is already a bit special compared to the other dbg scripts: $ ./scripts/dbgblock.py disk -b4096 0 1 -n16 block 0x0, size 16, cksum a90f45b6 00000000: 68 69 21 0e 00 03 00 08 6c 69 74 74 6c 65 66 73 hi!.....littlefs block 0x1, size 16, cksum 01e5f5e4 00000000: 68 69 21 0c 80 03 00 08 6c 69 74 74 6c 65 66 73 hi!.....littlefs This matches dbgcat.py, which is useful when switching between the two for debugging pipelines, etc. We want dbgblock.py/dbgcat.py to be as identical as possible, and if you removed the multiple blocks from dbgcat.py you'd have to really start asking why it's named dbgCAT.py.
212 lines
6.4 KiB
Python
Executable File
212 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# prevent local imports
|
|
if __name__ == "__main__":
|
|
__import__('sys').path.pop(0)
|
|
|
|
import itertools as it
|
|
import os
|
|
|
|
|
|
# some ways of block geometry representations
|
|
# 512 -> 512
|
|
# 512x16 -> (512, 16)
|
|
# 0x200x10 -> (512, 16)
|
|
def bdgeom(s):
|
|
s = s.strip()
|
|
b = 10
|
|
if s.startswith('0x') or s.startswith('0X'):
|
|
s = s[2:]
|
|
b = 16
|
|
elif s.startswith('0o') or s.startswith('0O'):
|
|
s = s[2:]
|
|
b = 8
|
|
elif s.startswith('0b') or s.startswith('0B'):
|
|
s = s[2:]
|
|
b = 2
|
|
|
|
if 'x' in s:
|
|
s, s_ = s.split('x', 1)
|
|
return (int(s, b), int(s_, b))
|
|
else:
|
|
return int(s, b)
|
|
|
|
# parse some rbyd addr encodings
|
|
# 0xa -> (0xa,)
|
|
# 0xa.c -> ((0xa, 0xc),)
|
|
# 0x{a,b} -> (0xa, 0xb)
|
|
# 0x{a,b}.c -> ((0xa, 0xc), (0xb, 0xc))
|
|
def rbydaddr(s):
|
|
s = s.strip()
|
|
b = 10
|
|
if s.startswith('0x') or s.startswith('0X'):
|
|
s = s[2:]
|
|
b = 16
|
|
elif s.startswith('0o') or s.startswith('0O'):
|
|
s = s[2:]
|
|
b = 8
|
|
elif s.startswith('0b') or s.startswith('0B'):
|
|
s = s[2:]
|
|
b = 2
|
|
|
|
trunk = None
|
|
if '.' in s:
|
|
s, s_ = s.split('.', 1)
|
|
trunk = int(s_, b)
|
|
|
|
if s.startswith('{') and '}' in s:
|
|
ss = s[1:s.find('}')].split(',')
|
|
else:
|
|
ss = [s]
|
|
|
|
addr = []
|
|
for s in ss:
|
|
if trunk is not None:
|
|
addr.append((int(s, b), trunk))
|
|
else:
|
|
addr.append(int(s, b))
|
|
|
|
return tuple(addr)
|
|
|
|
def xxd(data, width=16):
|
|
for i in range(0, len(data), width):
|
|
yield '%-*s %-*s' % (
|
|
3*width,
|
|
' '.join('%02x' % b for b in data[i:i+width]),
|
|
width,
|
|
''.join(
|
|
b if b >= ' ' and b <= '~' else '.'
|
|
for b in map(chr, data[i:i+width])))
|
|
|
|
def crc32c(data, crc=0):
|
|
crc ^= 0xffffffff
|
|
for b in data:
|
|
crc ^= b
|
|
for j in range(8):
|
|
crc = (crc >> 1) ^ ((crc & 1) * 0x82f63b78)
|
|
return 0xffffffff ^ crc
|
|
|
|
def main(disk, blocks=None, *,
|
|
block_size=None,
|
|
block_count=None,
|
|
off=None,
|
|
size=None,
|
|
cksum=False):
|
|
# is bd geometry specified?
|
|
if isinstance(block_size, tuple):
|
|
block_size, block_count_ = block_size
|
|
if block_count is None:
|
|
block_count = block_count_
|
|
|
|
with open(disk, 'rb') as f:
|
|
# if block_size is omitted, assume the block device is one big block
|
|
if block_size is None:
|
|
f.seek(0, os.SEEK_END)
|
|
block_size = f.tell()
|
|
|
|
# if block_count is omitted, derive the block_count from our file size
|
|
if block_count is None:
|
|
f.seek(0, os.SEEK_END)
|
|
block_count = f.tell() // block_size
|
|
|
|
# flatten blocks, default to block 0
|
|
blocks = (list(it.chain.from_iterable(
|
|
range(block.start or 0, block.stop or block_count)
|
|
if isinstance(block, slice)
|
|
else block
|
|
for block in blocks))
|
|
if blocks
|
|
else [0])
|
|
|
|
# blocks may also encode offsets
|
|
blocks, offs, size = (
|
|
[block[0] if isinstance(block, tuple)
|
|
else block
|
|
for block in blocks],
|
|
[off.start if isinstance(off, slice)
|
|
else off if off is not None
|
|
else size.start if isinstance(size, slice)
|
|
else block[1] if isinstance(block, tuple)
|
|
else None
|
|
for block in blocks],
|
|
(size.stop - (size.start or 0)
|
|
if size.stop is not None
|
|
else None) if isinstance(size, slice)
|
|
else size if size is not None
|
|
else ((off.stop - (off.start or 0))
|
|
if off.stop is not None
|
|
else None) if isinstance(off, slice)
|
|
else None)
|
|
|
|
# hexdump the blocks
|
|
for block, off in zip(blocks, offs):
|
|
block_ = block if block is not None else 0
|
|
off_ = off if off is not None else 0
|
|
size_ = size if size is not None else block_size - off_
|
|
|
|
# read the block
|
|
f.seek((block_ * block_size) + off_)
|
|
data = f.read(size_)
|
|
|
|
# calculate checksum
|
|
cksum = crc32c(data)
|
|
|
|
# print the header
|
|
print('block %s, size %d, cksum %08x' % (
|
|
'0x%x.%x' % (block_, off_)
|
|
if off is not None
|
|
else '0x%x' % block_,
|
|
size_,
|
|
cksum))
|
|
|
|
# render the hex view
|
|
for o, line in enumerate(xxd(data)):
|
|
print('%08x: %s' % (off_ + 16*o, line))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
import sys
|
|
parser = argparse.ArgumentParser(
|
|
description="Debug block devices.",
|
|
allow_abbrev=False)
|
|
parser.add_argument(
|
|
'disk',
|
|
help="File containing the block device.")
|
|
parser.add_argument(
|
|
'blocks',
|
|
nargs='*',
|
|
type=lambda x: (
|
|
slice(*(int(x, 0) if x.strip() else None
|
|
for x in x.split(',', 1)))
|
|
if ',' in x and '{' not in x
|
|
else rbydaddr(x)),
|
|
help="Block addresses, may be a range.")
|
|
parser.add_argument(
|
|
'-b', '--block-size',
|
|
type=bdgeom,
|
|
help="Block size/geometry in bytes.")
|
|
parser.add_argument(
|
|
'--block-count',
|
|
type=lambda x: int(x, 0),
|
|
help="Block count in blocks.")
|
|
parser.add_argument(
|
|
'--off',
|
|
type=lambda x: (
|
|
slice(*(int(x, 0) if x.strip() else None
|
|
for x in x.split(',', 1)))
|
|
if ',' in x
|
|
else int(x, 0)),
|
|
help="Show a specific offset, may be a range.")
|
|
parser.add_argument(
|
|
'-n', '--size',
|
|
type=lambda x: (
|
|
slice(*(int(x, 0) if x.strip() else None
|
|
for x in x.split(',', 1)))
|
|
if ',' in x
|
|
else int(x, 0)),
|
|
help="Show this many bytes, may be a range.")
|
|
sys.exit(main(**{k: v
|
|
for k, v in vars(parser.parse_intermixed_args()).items()
|
|
if v is not None}))
|