mirror of
https://github.com/LIV2/amitools.git
synced 2025-12-06 06:32:47 +00:00
refactored hunk scanner
This commit is contained in:
parent
dab43e3723
commit
256b9e7c78
@ -5,23 +5,28 @@ from pyadf import Adf, AdfIOException
|
||||
ST_DIR = 2
|
||||
ST_FILE = -3
|
||||
|
||||
def scan_dir(file_name, visit_func, dir_path, adf):
|
||||
entries = adf.ls_dir(dir_path)
|
||||
for entry in entries:
|
||||
name = entry.fname
|
||||
if dir_path == "":
|
||||
path = name
|
||||
else:
|
||||
path = dir_path + "/" + name
|
||||
if entry.ftype == ST_DIR:
|
||||
scan_dir(file_name, visit_func, path, adf)
|
||||
elif entry.ftype == ST_FILE:
|
||||
try:
|
||||
data = adf.get_file(path)
|
||||
visit_func(file_name, path, data)
|
||||
except AdfIOException, info:
|
||||
pass
|
||||
class ADFScanner:
|
||||
|
||||
def scan_adf(file_name, visit_func):
|
||||
adf = Adf(file_name, mode='r')
|
||||
scan_dir(file_name, visit_func, "", adf)
|
||||
def __init__(self, handler):
|
||||
self.handler = handler
|
||||
|
||||
def scan_dir(self, file_name, dir_path, adf):
|
||||
entries = adf.ls_dir(dir_path)
|
||||
for entry in entries:
|
||||
name = entry.fname
|
||||
if dir_path == "":
|
||||
path = name
|
||||
else:
|
||||
path = dir_path + "/" + name
|
||||
if entry.ftype == ST_DIR:
|
||||
self.scan_dir(file_name, path, adf)
|
||||
elif entry.ftype == ST_FILE:
|
||||
try:
|
||||
data = adf.get_file(path)
|
||||
self.handler(file_name, path, data)
|
||||
except AdfIOException, info:
|
||||
pass
|
||||
|
||||
def scan_adf(self, file_name):
|
||||
adf = Adf(file_name, mode='r')
|
||||
self.scan_dir(file_name, "", adf)
|
||||
|
||||
118
amitools/Hunk.py
118
amitools/Hunk.py
@ -31,32 +31,36 @@ HUNK_RELOC32SHORT = 1020
|
||||
HUNK_RELRELOC32 = 1021
|
||||
HUNK_ABSRELOC16 = 1022
|
||||
|
||||
hunk_names = [
|
||||
"HUNK_UNIT",
|
||||
"HUNK_NAME",
|
||||
"HUNK_CODE",
|
||||
"HUNK_DATA",
|
||||
"HUNK_BSS",
|
||||
"HUNK_ABSRELOC32",
|
||||
"HUNK_RELRELOC16",
|
||||
"HUNK_RELRELOC8",
|
||||
"HUNK_EXT",
|
||||
"HUNK_SYMBOL",
|
||||
"HUNK_DEBUG",
|
||||
"HUNK_END",
|
||||
"HUNK_HEADER",
|
||||
"",
|
||||
"HUNK_OVERLAY",
|
||||
"HUNK_BREAK",
|
||||
"HUNK_DREL32",
|
||||
"HUNK_DREL16",
|
||||
"HUNK_DREL8",
|
||||
"HUNK_LIB",
|
||||
"HUNK_INDEX",
|
||||
"HUNK_RELOC32SHORT",
|
||||
"HUNK_RELRELOC32",
|
||||
"HUNK_ABSRELOC16"
|
||||
]
|
||||
HUNK_PPC_CODE = 1257
|
||||
HUNK_RELRELOC26 = 1260
|
||||
|
||||
hunk_names = {
|
||||
HUNK_UNIT : "HUNK_UNIT",
|
||||
HUNK_NAME : "HUNK_NAME",
|
||||
HUNK_CODE : "HUNK_CODE",
|
||||
HUNK_DATA : "HUNK_DATA",
|
||||
HUNK_BSS : "HUNK_BSS",
|
||||
HUNK_ABSRELOC32 : "HUNK_ABSRELOC32",
|
||||
HUNK_RELRELOC16 : "HUNK_RELRELOC16",
|
||||
HUNK_RELRELOC8 : "HUNK_RELRELOC8",
|
||||
HUNK_EXT : "HUNK_EXT",
|
||||
HUNK_SYMBOL : "HUNK_SYMBOL",
|
||||
HUNK_DEBUG : "HUNK_DEBUG",
|
||||
HUNK_END : "HUNK_END",
|
||||
HUNK_HEADER : "HUNK_HEADER",
|
||||
HUNK_OVERLAY : "HUNK_OVERLAY",
|
||||
HUNK_BREAK : "HUNK_BREAK",
|
||||
HUNK_DREL32 : "HUNK_DREL32",
|
||||
HUNK_DREL16 : "HUNK_DREL16",
|
||||
HUNK_DREL8 : "HUNK_DREL8",
|
||||
HUNK_LIB : "HUNK_LIB",
|
||||
HUNK_INDEX : "HUNK_INDEX",
|
||||
HUNK_RELOC32SHORT : "HUNK_RELOC32SHORT",
|
||||
HUNK_RELRELOC32 : "HUNK_RELRELOC32",
|
||||
HUNK_ABSRELOC16 : "HUNK_ABSRELOC16",
|
||||
HUNK_PPC_CODE : "HUNK_PPC_CODE",
|
||||
HUNK_RELRELOC26 : "HUNK_RELRELOC26"
|
||||
}
|
||||
|
||||
EXT_SYMB = 0
|
||||
EXT_DEF = 1
|
||||
@ -100,6 +104,13 @@ RESULT_NO_HUNK_FILE = 1
|
||||
RESULT_INVALID_HUNK_FILE = 2
|
||||
RESULT_UNSUPPORTED_HUNKS = 3
|
||||
|
||||
result_names = {
|
||||
RESULT_OK : "RESULT_OK",
|
||||
RESULT_NO_HUNK_FILE : "RESULT_NO_HUNK_FILE",
|
||||
RESULT_INVALID_HUNK_FILE : "RESULT_INVALID_HUNK_FILE",
|
||||
RESULT_UNSUPPORTED_HUNKS : "RESULT_UNSUPPORTED_HUNKS"
|
||||
}
|
||||
|
||||
HUNKF_ADVISORY = 1<<29
|
||||
HUNKF_CHIP = 1<<30
|
||||
HUNKF_FAST = 1<<31
|
||||
@ -114,7 +125,6 @@ class HunkFile:
|
||||
def __init__(self):
|
||||
self.hunks = []
|
||||
self.error_string = None
|
||||
self.v37_compat = True
|
||||
|
||||
def read_long(self, f):
|
||||
data = f.read(4)
|
||||
@ -160,8 +170,7 @@ class HunkFile:
|
||||
return strtab[offset:end]
|
||||
|
||||
def is_valid_first_hunk_type(self, hunk_type):
|
||||
return hunk_type == HUNK_HEADER or hunk_type == HUNK_LIB or hunk_type == HUNK_UNIT \
|
||||
or hunk_type == HUNK_CODE # strange?
|
||||
return hunk_type == HUNK_HEADER or hunk_type == HUNK_LIB or hunk_type == HUNK_UNIT
|
||||
|
||||
def parse_header(self, f, hunk):
|
||||
names = []
|
||||
@ -417,7 +426,7 @@ class HunkFile:
|
||||
total_size -= 6
|
||||
name = self.get_index_name(strtab, name_offset)
|
||||
d = { 'name':name, 'value':def_value,'type':def_type}
|
||||
set_mem_flags(d,def_flags,14)
|
||||
self.set_mem_flags(d,def_flags,14)
|
||||
defs.append(d)
|
||||
|
||||
# align hunk
|
||||
@ -499,19 +508,21 @@ class HunkFile:
|
||||
"""Read a hunk file and build internal hunk structure
|
||||
Return status and set self.error_string on failure
|
||||
"""
|
||||
def read_file(self, hfile):
|
||||
def read_file(self, hfile, v37_compat=None):
|
||||
with open(hfile) as f:
|
||||
return self.read_file_obj(hfile, f)
|
||||
return self.read_file_obj(hfile, f, v37_compat)
|
||||
|
||||
"""Read a hunk from memory"""
|
||||
def read_mem(self, name, data):
|
||||
def read_mem(self, name, data, v37_compat=None):
|
||||
fobj = StringIO.StringIO(data)
|
||||
return self.read_file_obj(name, fobj)
|
||||
return self.read_file_obj(name, fobj, v37_compat)
|
||||
|
||||
def read_file_obj(self, hfile, f):
|
||||
def read_file_obj(self, hfile, f, v37_compat):
|
||||
self.hunks = []
|
||||
is_first_hunk = True
|
||||
was_end = False
|
||||
was_potentail_v37_hunk = False
|
||||
self.error_string = None
|
||||
|
||||
while True:
|
||||
# read hunk type
|
||||
@ -531,40 +542,51 @@ class HunkFile:
|
||||
hunk_flags = hunk_raw_type & HUNK_FLAGS_MASK
|
||||
|
||||
# check range of hunk type
|
||||
if hunk_type < HUNK_MIN or hunk_type > HUNK_MAX:
|
||||
if not hunk_names.has_key(hunk_type):
|
||||
# no hunk file?
|
||||
if is_first_hunk:
|
||||
self.error_string = "No valid hunk file: '%s' type was %d" % (hfile, hunk_type)
|
||||
self.error_string = "No hunk file: '%s' type was %d" % (hfile, hunk_type)
|
||||
return RESULT_NO_HUNK_FILE
|
||||
elif was_end:
|
||||
# garbage after an end tag is ignored
|
||||
return RESULT_OK
|
||||
elif was_potentail_v37_hunk:
|
||||
# auto fix v37 -> reread whole file
|
||||
f.seek(0)
|
||||
return self.read_file_obj(hfile, f, True)
|
||||
else:
|
||||
self.error_string = "Invalid hunk type %d found at @%08x" % (hunk_type,f.tell())
|
||||
self.error_string = "Invalid hunk type %d/%x found at @%08x" % (hunk_type,hunk_type,f.tell())
|
||||
return RESULT_INVALID_HUNK_FILE
|
||||
else:
|
||||
# check for valid first hunk type
|
||||
if is_first_hunk and not self.is_valid_first_hunk_type(hunk_type):
|
||||
self.error_string = "No valid hunk file: '%s' first hunk type was %d" % (hfile, hunk_type)
|
||||
return RESULT_INVALID_HUNK_FILE
|
||||
self.error_string = "No hunk file: '%s' first hunk type was %d" % (hfile, hunk_type)
|
||||
return RESULT_NO_HUNK_FILE
|
||||
|
||||
is_first_hunk = False
|
||||
was_end = False
|
||||
was_potentail_v37_hunk = False
|
||||
|
||||
hunk = { 'type' : hunk_type }
|
||||
self.hunks.append(hunk)
|
||||
hunk['type_name'] = hunk_names[hunk_type - HUNK_MIN]
|
||||
hunk['type_name'] = hunk_names[hunk_type]
|
||||
self.set_mem_flags(hunk, hunk_flags, 30)
|
||||
|
||||
# V37 fix
|
||||
if self.v37_compat and hunk_type == HUNK_DREL32:
|
||||
hunk_type = HUNK_RELOC32SHORT
|
||||
# V37 fix?
|
||||
if hunk_type == HUNK_DREL32:
|
||||
# try to fix automatically...
|
||||
if v37_compat == None:
|
||||
was_potentail_v37_hunk = True
|
||||
# fix was forced
|
||||
elif v37_compat:
|
||||
hunk_type = HUNK_RELOC32SHORT
|
||||
hunk['fixes'] = 'v37'
|
||||
|
||||
# ----- HUNK_HEADER -----
|
||||
if hunk_type == HUNK_HEADER:
|
||||
result = self.parse_header(f,hunk)
|
||||
# ----- HUNK_CODE/HUNK_DATA ------
|
||||
elif hunk_type == HUNK_CODE or hunk_type == HUNK_DATA:
|
||||
elif hunk_type == HUNK_CODE or hunk_type == HUNK_DATA or hunk_type == HUNK_PPC_CODE:
|
||||
result = self.parse_code_or_data(f,hunk)
|
||||
# ---- HUNK_BSS ----
|
||||
elif hunk_type == HUNK_BSS:
|
||||
@ -574,6 +596,10 @@ class HunkFile:
|
||||
or hunk_type == HUNK_RELRELOC8 or hunk_type == HUNK_RELRELOC16 or hunk_type == HUNK_ABSRELOC32 \
|
||||
or hunk_type ==HUNK_DREL32 or hunk_type == HUNK_DREL16 or hunk_type == HUNK_DREL8:
|
||||
result = self.parse_reloc(f,hunk)
|
||||
# auto fix v37 bug?
|
||||
if hunk_type == HUNK_DREL32 and result != RESULT_OK and v37_compat == None:
|
||||
f.seek(0)
|
||||
return self.read_file_obj(hfile, f, True)
|
||||
# ---- HUNK_<reloc short> -----
|
||||
elif hunk_type == HUNK_RELOC32SHORT:
|
||||
result = self.parse_reloc_short(f,hunk)
|
||||
@ -614,5 +640,5 @@ class HunkFile:
|
||||
if result != RESULT_OK:
|
||||
return result
|
||||
|
||||
return RESULT_OK
|
||||
return RESULT_OK
|
||||
|
||||
|
||||
53
amitools/HunkScanner.py
Normal file
53
amitools/HunkScanner.py
Normal file
@ -0,0 +1,53 @@
|
||||
# scan a set of hunks
|
||||
|
||||
import os
|
||||
import Hunk
|
||||
|
||||
class HunkScanner:
|
||||
|
||||
def __init__(self, handler, use_adf = False, ignore_no_hunk = True):
|
||||
self.ignore_no_hunk = ignore_no_hunk
|
||||
self.handler = handler
|
||||
if use_adf:
|
||||
import ADFScanner
|
||||
self.adf_scanner = ADFScanner.ADFScanner(lambda a,b,c: self.handle_adf_file(a,b,c))
|
||||
else:
|
||||
self.adf_scanner = None
|
||||
|
||||
def call_handler(self, path, hunk_file, return_code):
|
||||
if return_code == Hunk.RESULT_NO_HUNK_FILE and self.ignore_no_hunk:
|
||||
return
|
||||
self.handler(path, hunk_file, return_code)
|
||||
|
||||
def handle_adf_file(self, img_path, file_path, data):
|
||||
vpath = img_path + ":" + file_path
|
||||
hf = Hunk.HunkFile()
|
||||
result = hf.read_mem(vpath, data)
|
||||
self.call_handler(vpath, hf, result)
|
||||
|
||||
def handle_adf(self, path):
|
||||
if self.adf_scanner != None:
|
||||
self.adf_scanner.scan_adf(path)
|
||||
|
||||
def handle_file(self, path):
|
||||
if path.lower().endswith(".adf"):
|
||||
self.handle_adf(path)
|
||||
return
|
||||
|
||||
hf = Hunk.HunkFile()
|
||||
result = hf.read_file(path)
|
||||
self.call_handler(path, hf, result)
|
||||
|
||||
def handle_dir(self, path):
|
||||
for root, dirs, files in os.walk(path):
|
||||
for name in files:
|
||||
self.handle_file(os.path.join(root,name))
|
||||
for name in dirs:
|
||||
self.handle_dir(os.path.join(root,name))
|
||||
|
||||
def handle_path(self, path):
|
||||
if os.path.isdir(path):
|
||||
self.handle_dir(path)
|
||||
elif os.path.isfile(path):
|
||||
self.handle_file(path)
|
||||
|
||||
90
hunktool
90
hunktool
@ -6,81 +6,49 @@
|
||||
#
|
||||
# written by Christian Vogelgsang (chris@vogelgsang.org)
|
||||
|
||||
import os, sys
|
||||
import sys
|
||||
import argparse
|
||||
import pprint
|
||||
|
||||
from amitools.HunkScanner import HunkScanner
|
||||
from amitools import Hunk
|
||||
from amitools import ADFScanner
|
||||
|
||||
def show_hunks_brief(hunks):
|
||||
for hunk in hunks:
|
||||
print hunk['name']
|
||||
|
||||
def dump_hunks(hunks):
|
||||
def print_pretty(data):
|
||||
pp = pprint.PrettyPrinter(indent=2)
|
||||
pp.pprint(hunks)
|
||||
pp.pprint(data)
|
||||
|
||||
# ----- handle paths -----
|
||||
# ----- commands -----
|
||||
|
||||
def check_file(path, hunk_file, result):
|
||||
if result == Hunk.RESULT_OK:
|
||||
print path,"OK"
|
||||
class Validator:
|
||||
def __init__(self, args):
|
||||
self.counts = {}
|
||||
self.args = args
|
||||
|
||||
def handle_file(self, path, hunk_file, error_code):
|
||||
if not self.counts.has_key(error_code):
|
||||
self.counts[error_code] = 0
|
||||
self.counts[error_code] += 1
|
||||
print path, error_code, hunk_file.error_string
|
||||
if args.dump:
|
||||
dump_hunks(hunk_file.hunks)
|
||||
elif result == Hunk.RESULT_NO_HUNK_FILE:
|
||||
#print "No:",path,hunk_file.error_string
|
||||
pass
|
||||
elif result == Hunk.RESULT_INVALID_HUNK_FILE:
|
||||
print path,"Invalid:",hunk_file.error_string
|
||||
if args.dump:
|
||||
dump_hunks(hunk_file.hunks)
|
||||
sys.exit(1)
|
||||
elif result == Hunk.RESULT_UNSUPPORTED_HUNKS:
|
||||
print path,"Unsupported:",hunk_file.error_string
|
||||
if args.dump:
|
||||
dump_hunks(hunk_file.hunks)
|
||||
sys.exit(1)
|
||||
|
||||
def handle_adf_file(img_path,file_path,data):
|
||||
vpath = img_path + ":" + file_path
|
||||
hf = Hunk.HunkFile()
|
||||
result = hf.read_mem(vpath, data)
|
||||
check_file(vpath, hf, result)
|
||||
|
||||
def handle_adf(path):
|
||||
ADFScanner.scan_adf(path, handle_adf_file)
|
||||
|
||||
def handle_file(path):
|
||||
global args
|
||||
print_pretty(hunk_file.hunks)
|
||||
|
||||
if path.endswith(".adf"):
|
||||
handle_adf(path)
|
||||
return
|
||||
|
||||
hf = Hunk.HunkFile()
|
||||
result = hf.read_file(path)
|
||||
check_file(path, hf, result)
|
||||
|
||||
def handle_dir(path):
|
||||
for root, dirs, files in os.walk(path):
|
||||
for name in files:
|
||||
handle_file(os.path.join(root,name))
|
||||
for name in dirs:
|
||||
handle_dir(os.path.join(root,name))
|
||||
|
||||
def handle_path(path):
|
||||
if os.path.isdir(path):
|
||||
handle_dir(path)
|
||||
elif os.path.isfile(path):
|
||||
handle_file(path)
|
||||
def result(self):
|
||||
for code in self.counts.keys():
|
||||
print Hunk.result_names[code],":",self.counts[code]
|
||||
return 0
|
||||
|
||||
# ----- main -----
|
||||
parser = argparse.ArgumentParser()
|
||||
#parser.add_argument('command')
|
||||
parser.add_argument('hunkfiles', nargs='+')
|
||||
parser.add_argument('-d', '--dump', action='store_true', default=False, help="dump the hunk structure")
|
||||
parser.add_argument('-a', '--adf', action='store_true', default=False, help="enable adf scanner (requires adflib)")
|
||||
args = parser.parse_args()
|
||||
|
||||
for p in args.hunkfiles:
|
||||
handle_path(p)
|
||||
print "done"
|
||||
# call scanner and process all files with selected command
|
||||
cmd = Validator(args)
|
||||
scanner = HunkScanner(cmd.handle_file, use_adf=args.adf)
|
||||
for path in args.hunkfiles:
|
||||
scanner.handle_path(path)
|
||||
res = cmd.result()
|
||||
sys.exit(res)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user