mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-01 12:20:02 +00:00
- Tried to do the rescaling a bit better with truncating divisions, so there shouldn't be weird cross-pixel updates when things aren't well aligned. - Adopted optional -B<block_size>x<block_count> flag for explicitly specifying the block-device geometry in a way that is compatible with other scripts. Should adopt this more places. - Adopted optional <block>.<off> argument for start of range. This should match dbgblock.py. - Adopted '-' for noop/zero-wear. - Renamed a few internal things. - Dropped subscript chars for wear, this didn't really add anything and can be accomplished by specifying the --wear-chars explicitly. Also changed dbgblock.py to match, this mostly affects the --off/-n/--size flags. For example, these are all the same: ./scripts/dbgblock.py disk -B4096 --off=10 --size=5 ./scripts/dbgblock.py disk -B4096 --off=10 -n5 ./scripts/dbgblock.py disk -B4096 --off=10,15 ./scripts/dbgblock.py disk -B4096 -n10,15 ./scripts/dbgblock.py disk -B4096 0.10 -n5 Also also adopted block-device geometry argument across scripts, where the -B flag can optionally be a full <block_size>x<block_count> geometry: ./scripts/tracebd.py disk -B4096x256 Though this is mostly unused outside of tracebd.py right now. It will be useful for anything that formats littlefs (littlefs-fuse?) and allowing the format everywhere is a bit of a nice convenience.
168 lines
4.6 KiB
Python
Executable File
168 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
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 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 main(disk, block=None, *,
|
|
block_size=None,
|
|
block_count=None,
|
|
off=None,
|
|
size=None):
|
|
# is bd geometry specified?
|
|
if isinstance(block_size, tuple):
|
|
block_size, block_count_ = block_size
|
|
if block_count is None:
|
|
block_count = block_count_
|
|
|
|
# flatten block, default to block 0
|
|
if not block:
|
|
block = [0]
|
|
|
|
if len(block) > 1:
|
|
print("error: More than one block address?")
|
|
sys.exit(-1)
|
|
|
|
block = block[0]
|
|
|
|
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()
|
|
|
|
# block may also encode an offset
|
|
block, off, size = (
|
|
block[0] if isinstance(block, tuple) else block,
|
|
off[0] if isinstance(off, tuple)
|
|
else off if off is not None
|
|
else size[0] if isinstance(size, tuple) and len(size) > 1
|
|
else block[1] if isinstance(block, tuple)
|
|
else None,
|
|
size[1] - size[0] if isinstance(size, tuple) and len(size) > 1
|
|
else size[0] if isinstance(size, tuple)
|
|
else size if size is not None
|
|
else off[1] - off[0] if isinstance(off, tuple) and len(off) > 1
|
|
else block_size)
|
|
|
|
print('block %s, size %d' % (
|
|
'0x%x.%x' % (block, off)
|
|
if off is not None
|
|
else '0x%x' % block,
|
|
size))
|
|
|
|
# read the block
|
|
f.seek((block * block_size) + (off or 0))
|
|
data = f.read(size)
|
|
|
|
# render the hex view
|
|
for o, line in enumerate(xxd(data)):
|
|
print('%08x: %s' % ((off or 0) + 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(
|
|
'block',
|
|
nargs='?',
|
|
type=rbydaddr,
|
|
help="Block address.")
|
|
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: tuple(
|
|
int(x, 0) if x.strip() else None
|
|
for x in x.split(',')),
|
|
help="Show a specific offset, may be a range.")
|
|
parser.add_argument(
|
|
'-n', '--size',
|
|
type=lambda x: tuple(
|
|
int(x, 0) if x.strip() else None
|
|
for x in x.split(',')),
|
|
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}))
|