1
0
mirror of https://github.com/weiju/amiga-stuff synced 2025-11-21 09:19:45 +00:00
Files
amiga-stuff/hunktools/hunk.py
2014-11-07 16:06:19 -08:00

179 lines
6.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""A tool like dalf.rexx that can be used to inspect the structure of
an Amiga Hunk file.
"""
import argparse
import struct
from disassemble import disassemble, print_instruction
HUNK_BLOCK_UNIT = b'\x00\x00\x03\xe7'
HUNK_BLOCK_NAME = b'\x00\x00\x03\xe8'
HUNK_BLOCK_CODE = b'\x00\x00\x03\xe9'
HUNK_BLOCK_DATA = b'\x00\x00\x03\xea'
HUNK_BLOCK_BSS = b'\x00\x00\x03\xeb'
HUNK_BLOCK_RELOC32 = b'\x00\x00\x03\xec'
HUNK_BLOCK_RELOC16 = b'\x00\x00\x03\xed'
HUNK_BLOCK_RELOC8 = b'\x00\x00\x03\xee'
HUNK_BLOCK_EXT = b'\x00\x00\x03\xef'
HUNK_BLOCK_SYMBOL = b'\x00\x00\x03\xf0'
HUNK_BLOCK_DEBUG = b'\x00\x00\x03\xf1'
HUNK_BLOCK_END = b'\x00\x00\x03\xf2'
HUNK_BLOCK_HEADER = b'\x00\x00\x03\xf3'
HUNK_BLOCK_OVERLAY = b'\x00\x00\x03\xf5'
HUNK_BLOCK_BREAK = b'\x00\x00\x03\xf6'
HUNK_BLOCK_DRELOC32 = b'\x00\x00\x03\xf7'
HUNK_BLOCK_DRELOC16 = b'\x00\x00\x03\xf8'
HUNK_BLOCK_DRELOC8 = b'\x00\x00\x03\xf9'
HUNK_BLOCK_RELOC32SHORT = b'\x00\x00\x03\xfc'
# new library file
HUNK_BLOCK_LIB = b'\x00\x00\x03\xfb'
HUNK_BLOCK_INDEX = b'\x00\x00\x03\xfc'
def read_int32(infile):
return struct.unpack('>i', infile.read(4))[0]
def read_int16(infile):
return struct.unpack('>h', infile.read(2))[0]
def read_string_list(infile):
result = []
strlen = read_int32(infile)
while strlen > 0:
result.append(str(infile.read(strlen)))
strlen = read_int32(infile)
return []
def read_raw_bytes(infile):
num_bytes = read_int32(infile) * 4
data = infile.read(num_bytes)
if len(data) < num_bytes:
print("WARNING: tried to read %d bytes, but only %d bytes could be read" % (num_bytes,
bytes_read))
return data
def read_reloc32map(infile):
num_offsets = read_int32(infile)
result = {}
while num_offsets > 0:
hunknum = read_int32(infile)
hunk_offsets = [read_int32(infile) for i in range(num_offsets)]
result[hunknum] = hunk_offsets
num_offsets = read_int32(infile)
return result
def read_reloc16map(infile):
num_offsets = read_int16(infile)
total_offsets = num_offsets
result = {}
while num_offsets > 0:
hunknum = read_int16(infile)
hunk_offsets = [read_int16(infile) for i in range(num_offsets)]
result[hunknum] = hunk_offsets
num_offsets = read_int16(infile)
total_offsets += num_offsets
if (total_offsets % 2) == 0:
read_int16(infile)
return result
def read_block(infile, is_loadfile):
id = infile.read(4)
if len(id) == 0: # end of input
return None
if id == HUNK_BLOCK_CODE:
return ('CODE', read_raw_bytes(infile))
elif id == HUNK_BLOCK_RELOC32:
return ('RELOC32', read_reloc32map(infile))
elif id == HUNK_BLOCK_END:
return ('END', None)
elif id == HUNK_BLOCK_DRELOC32:
if is_loadfile:
return ('RELOC32SHORT', read_reloc16map(infile))
else:
return ('RELOC32', read_reloc32map(infile))
elif id == HUNK_BLOCK_DATA:
return ('DATA', read_raw_bytes(infile))
elif id == HUNK_BLOCK_BSS:
return ('BSS', read_int32(infile) * 4)
elif id == HUNK_BLOCK_NAME:
return ('NAME', str(infile.read(read_int32(infile) * 4)))
else:
raise Exception("unsupported id: %s" % id)
return None
def read_blocks(infile, is_loadfile):
result = []
block = read_block(infile, is_loadfile)
while block is not None:
result.append(block)
block = read_block(infile, is_loadfile)
return result
def parse_hunkfile(hunkfile):
"""Top level parsing function"""
with open(hunkfile, 'rb') as infile:
id = infile.read(4)
# can be Header or Unit
is_loadfile = True
if id == HUNK_BLOCK_HEADER:
library_names = read_string_list(infile)
print("Libraries: ", library_names)
hunk_table_size = read_int32(infile)
print("size hunk table: %d" % hunk_table_size)
first_slot = read_int32(infile)
last_slot = read_int32(infile)
num_hunk_sizes = last_slot - first_slot + 1
print("first slot: %d, last slot: %d, # hunk sizes: %d" % (first_slot,
last_slot,
num_hunk_sizes))
hunk_sizes = [read_int32(infile) for i in range(num_hunk_sizes)]
print("hunk sizes: ", hunk_sizes)
elif id == HUNK_BLOCK_UNIT:
strlen = read_int32(infile) * 4
print("# name: %d" % strlen)
unit_name = str(infile.read(strlen))
print("UNIT '%s'" % unit_name)
else:
is_loadfile = False
raise Exception('Unsupported header type')
blocks = read_blocks(infile, is_loadfile)
print("%d blocks read: " % len(blocks))
for i, block in enumerate(blocks):
if block[0] == 'NAME':
print("Block %d: '%s' -> '%s'" % (i, block[0], block[1]))
elif block[0] == 'BSS':
print("Block %d: '%s' -> %d" % (i, block[0], block[1]))
elif block[0] == 'CODE':
print("%d: '%s'" % (i, block[0]))
code = block[1]
offset = 0
while offset < len(code):
op, size = disassemble(code, offset)
print_instruction(offset, op)
offset += size
else:
print("Block %d: '%s'" % (i, block[0]))
if __name__ == '__main__':
description = """hunk - hunk file reader (c) 2014 Wei-ju Wu"""
parser = argparse.ArgumentParser(description=description)
parser.add_argument('hunkfile', help="hunk format file")
args = parser.parse_args()
parse_hunkfile(args.hunkfile)