forked from cnvogelg/amitools
-
Notifications
You must be signed in to change notification settings - Fork 1
/
hunktool
executable file
·221 lines (188 loc) · 7.32 KB
/
hunktool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#!/usr/bin/env python2.7
#
# hunktool
#
# the swiss-army knife for Amiga Hunk executable file format
#
# written by Christian Vogelgsang (chris@vogelgsang.org)
import sys
import argparse
import pprint
import time
from amitools.FileScanner import FileScanner
from amitools.hunk import Hunk
from amitools.hunk import HunkReader
from amitools.hunk import HunkShow
from amitools.hunk import HunkRelocate
from amitools.elf import ELFReader
from amitools.util.HexDump import *
def print_pretty(data):
pp = pprint.PrettyPrinter(indent=2)
pp.pprint(data)
# ----- commands -------------------------------------------------------------
class HunkCommand:
def __init__(self, args):
self.counts = {}
self.args = args
self.failed_files = []
def handle_file(self, path, hunk_file, error_code, delta):
if not self.counts.has_key(error_code):
self.counts[error_code] = 0
self.counts[error_code] += 1
print "%s (%.4fs)" % (path, delta),
# abort if hunk parser failed!
if error_code != Hunk.RESULT_OK:
print Hunk.result_names[error_code], hunk_file.error_string
if args.dump:
print_pretty(hunk_file.hunks)
self.failed_files.append( (path, "READ: " + hunk_file.error_string) )
return not self.args.stop
# if verbose then print block structure
if args.verbose:
print
print " hunks: ",hunk_file.get_hunk_summary()
if args.dump:
print_pretty(hunk_file.hunks)
print " type: ",
# build segments from hunks
ok = hunk_file.build_segments()
if not ok:
print "BUILD SEGMENTS FAILED: %s" % (hunk_file.error_string)
self.failed_files.append( (path, "BUILD: " + hunk_file.error_string) )
return not self.args.stop
# print recognized file type name
print Hunk.type_names[hunk_file.type],
# if verbose then print hunk structure
if args.verbose:
print
print " segments: ",hunk_file.get_segment_summary()
print " overlays: ",hunk_file.get_overlay_segment_summary()
print " libs: ",hunk_file.get_libs_summary()
print " units: ",hunk_file.get_units_summary()
if args.dump:
print_pretty(hunk_file.hunks)
else:
print
# do special processing on hunk file for command
ok = self.handle_hunk_file(path, hunk_file)
return ok
def result(self):
for code in self.counts.keys():
print Hunk.result_names[code],":",self.counts[code]
for failed in self.failed_files:
print failed[0],failed[1]
return 0
def process_file(self, path, fobj, cmd):
hunk_file = HunkReader.HunkReader()
start = time.clock()
result = hunk_file.read_file_obj(path,fobj,None)
end = time.clock()
delta = end - start
# ignore non hunk files
if result == Hunk.RESULT_NO_HUNK_FILE:
return True
return self.handle_file(path, hunk_file, result, delta)
def run(self):
scanner = FileScanner(lambda path, fobj: self.process_file(path, fobj, cmd), use_adf=args.adf, use_lha=args.lha, stop_on_error=args.stop)
for path in args.files:
ok = scanner.handle_path(path)
if not ok:
print "ABORTED"
return cmd.result()
# ----- Validator -----
class Validator(HunkCommand):
def handle_hunk_file(self, path, hunk_file):
# do nothing extra
return True
# ----- Info -----
class Info(HunkCommand):
def handle_hunk_file(self, path, hunk_file):
# verbose all hunk
hs = HunkShow.HunkShow(hunk_file, \
show_relocs=args.show_relocs, show_debug=args.show_debug, \
disassemble=args.disassemble, disassemble_start=args.disassemble_start, \
use_objdump=args.use_objdump, cpu=args.cpu, \
hexdump=args.hexdump, \
brief=args.brief)
hs.show_segments()
return True
# ----- Relocate -----
class Relocate(HunkCommand):
def handle_hunk_file(self, path, hunk_file):
if hunk_file.type != Hunk.TYPE_LOADSEG:
print "ERROR: can only relocate LoadSeg()able files:",path;
return False
rel = HunkRelocate.HunkRelocate(hunk_file,verbose=self.args.verbose)
# get sizes of all segments
sizes = rel.get_sizes()
# calc begin addrs for all segments
base_addr = self.args.base_address
addrs = rel.get_seq_addrs(base_addr)
# relocate and return data of segments
datas = rel.relocate(addrs)
if datas == None:
print "ERROR: relocation failed:",path
return False
else:
print "Relocate to base address",base_addr
print "Bases: "," ".join(map(lambda x:"%06x"%(x),addrs))
print "Sizes: "," ".join(map(lambda x:"%06x"%(x),sizes))
print "Data: "," ".join(map(lambda x:"%06x"%(len(x)),datas))
print "Total: ","%06x"%(rel.get_total_size())
if args.hexdump:
for d in datas:
print_hex(d)
return True
# ----- Elf2Hunk -----
class ElfInfo:
def __init__(self,args):
self.args = args
def run(self):
for f in args.files:
elf = ELFReader.ELFReader()
if not elf.load(f):
print "ERROR loading ELF:",elf.error_string
return 1
elf.dump_elf_segment_headers()
elf.dump_elf_symbols()
elf.dump_elf_relas()
elf.dump_elf_segments(show_relocs=args.show_relocs, show_debug=args.show_debug)
return 0
# ----- main -----
# call scanner and process all files with selected command
cmd_map = {
"validate" : Validator,
"info" : Info,
"elfinfo" : ElfInfo,
"relocate" : Relocate
}
parser = argparse.ArgumentParser()
parser.add_argument('command', help="command: "+",".join(cmd_map.keys()))
parser.add_argument('files', nargs='+')
parser.add_argument('-d', '--dump', action='store_true', default=False, help="dump the hunk structure")
parser.add_argument('-v', '--verbose', action='store_true', default=False, help="be more verbos")
parser.add_argument('-a', '--adf', nargs='?', default='unadf', help="enable adf scanner (requires unadf tool)")
parser.add_argument('-l', '--lha', nargs='?', default='lha', help="enable lha scanner (with given lha executable)")
parser.add_argument('-s', '--stop', action='store_true', default=False, help="stop on error")
parser.add_argument('-R', '--show-relocs', action='store_true', default=False, help="show relocation entries")
parser.add_argument('-D', '--show-debug', action='store_true', default=False, help="show debug info entries")
parser.add_argument('-A', '--disassemble', action='store_true', default=False, help="disassemble code segments")
parser.add_argument('-S', '--disassemble-start', action='store', type=int, default=0, help="start address for dissassembly")
parser.add_argument('-x', '--hexdump', action='store_true', default=False, help="dump segments in hex")
parser.add_argument('-b', '--brief', action='store_true', default=False, help="show only brief information")
parser.add_argument('-B', '--base-address', action='store', type=int, default=0, help="base address for relocation")
parser.add_argument('-o', '--use-objdump', action='store_true', default=False, help="disassemble with m68k-elf-objdump instead of vda68k")
parser.add_argument('-c', '--cpu', action='store', default='68000', help="disassemble for given cpu (objdump only)")
args = parser.parse_args()
cmd = args.command
if not cmd_map.has_key(cmd):
print "INVALID COMMAND:",cmd
print "valid commands are:"
for a in cmd_map:
print " ",a
sys.exit(1)
cmd_cls = cmd_map[cmd]
# execute command
cmd = cmd_cls(args)
res = cmd.run()
sys.exit(res)