main
dis.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include "68kinst.h"
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <stdarg.h>
11#include <ctype.h>
12#include "vos_program_module.h"
13#include "tern.h"
14#include "util.h"
15
16uint8_t visited[(16*1024*1024)/16];
17uint16_t label[(16*1024*1024)/8];
18
19void fatal_error(char *format, ...)
20{
21 va_list args;
22 va_start(args, format);
23 vfprintf(stderr, format, args);
24 va_end(args);
25 exit(1);
26}
27
28
29void visit(uint32_t address)
30{
31 address &= 0xFFFFFF;
32 visited[address/16] |= 1 << ((address / 2) % 8);
33}
34
35void reference(uint32_t address)
36{
37 address &= 0xFFFFFF;
38 //printf("referenced: %X\n", address);
39 label[address/16] |= 1 << (address % 16);
40}
41
42uint8_t is_visited(uint32_t address)
43{
44 address &= 0xFFFFFF;
45 return visited[address/16] & (1 << ((address / 2) % 8));
46}
47
48uint16_t is_label(uint32_t address)
49{
50 address &= 0xFFFFFF;
51 return label[address/16] & (1 << (address % 16));
52}
53
54typedef struct {
55 uint32_t num_labels;
56 uint32_t storage;
57 char *labels[];
58} label_names;
59
60tern_node * add_label(tern_node * head, char * name, uint32_t address)
61{
62 char key[MAX_INT_KEY_SIZE];
63 address &= 0xFFFFFF;
64 reference(address);
65 tern_int_key(address, key);
66 label_names * names = tern_find_ptr(head, key);
67 if (names)
68 {
69 if (names->num_labels == names->storage)
70 {
71 names->storage = names->storage + (names->storage >> 1);
72 names = realloc(names, sizeof(label_names) + names->storage * sizeof(char *));
73 }
74 } else {
75 names = malloc(sizeof(label_names) + 4 * sizeof(char *));
76 names->num_labels = 0;
77 names->storage = 4;
78 head = tern_insert_ptr(head, key, names);
79 }
80 names->labels[names->num_labels++] = strdup(name);
81 return head;
82}
83
84typedef struct deferred {
85 uint32_t address;
86 struct deferred *next;
87} deferred;
88
89deferred * defer(uint32_t address, deferred * next)
90{
91 if (is_visited(address) || address & 1) {
92 return next;
93 }
94 //printf("deferring %X\n", address);
95 deferred * d = malloc(sizeof(deferred));
96 d->address = address;
97 d->next = next;
98 return d;
99}
100
101void check_reference(m68kinst * inst, m68k_op_info * op)
102{
103 switch(op->addr_mode)
104 {
105 case MODE_PC_DISPLACE:
106 reference(inst->address + 2 + op->params.regs.displacement);
107 break;
108 case MODE_ABSOLUTE:
109 case MODE_ABSOLUTE_SHORT:
110 reference(op->params.immed);
111 break;
112 }
113}
114
115int label_fun(char *dst, uint32_t address, void * data)
116{
117 tern_node * labels = data;
118 char key[MAX_INT_KEY_SIZE];
119 label_names * names = tern_find_ptr(labels, tern_int_key(address & 0xFFFFFF, key));
120 if (names)
121 {
122 return sprintf(dst, "%s", names->labels[0]);
123 } else {
124 return m68k_default_label_fun(dst, address, NULL);
125 }
126}
127
128char * strip_ws(char * text)
129{
130 while (*text && (!isprint(*text) || isblank(*text)))
131 {
132 text++;
133 }
134 char * ret = text;
135 text = ret + strlen(ret) - 1;
136 while (text > ret && (!isprint(*text) || isblank(*text)))
137 {
138 *text = 0;
139 text--;
140 }
141 return ret;
142}
143
144int main(int argc, char ** argv)
145{
146 long filesize;
147 unsigned short *filebuf;
148 char disbuf[1024];
149 m68kinst instbuf;
150 unsigned short * cur;
151 deferred *def = NULL, *tmpd;
152
153 uint8_t labels = 0, addr = 0, only = 0, vos = 0, reset = 0;
154 tern_node * named_labels = NULL;
155
156 uint32_t address_off = 0, address_end;
157 for(uint8_t opt = 2; opt < argc; ++opt) {
158 if (argv[opt][0] == '-') {
159 FILE * address_log;
160 switch (argv[opt][1])
161 {
162 case 'l':
163 labels = 1;
164 break;
165 case 'a':
166 addr = 1;
167 break;
168 case 'o':
169 only = 1;
170 break;
171 case 'v':
172 vos = 1;
173 break;
174 case 'r':
175 reset = 1;
176 break;
177 case 's':
178 opt++;
179 if (opt >= argc) {
180 fputs("-s must be followed by an offset\n", stderr);
181 exit(1);
182 }
183 address_off = strtol(argv[opt], NULL, 0);
184 break;
185 case 'f':
186 opt++;
187 if (opt >= argc) {
188 fputs("-f must be followed by a filename\n", stderr);
189 exit(1);
190 }
191 address_log = fopen(argv[opt], "r");
192 if (!address_log) {
193 fprintf(stderr, "Failed to open %s for reading\n", argv[opt]);
194 exit(1);
195 }
196 while (fgets(disbuf, sizeof(disbuf), address_log)) {
197 if (disbuf[0]) {
198 char *end;
199 uint32_t address = strtol(disbuf, &end, 16);
200 if (address) {
201 def = defer(address, def);
202 reference(address);
203 if (*end == '=') {
204 named_labels = add_label(named_labels, strip_ws(end+1), address);
205 }
206 }
207 }
208 }
209 fclose(address_log);
210 }
211 } else {
212 char *end;
213 uint32_t address = strtol(argv[opt], &end, 16);
214 def = defer(address, def);
215 reference(address);
216 if (*end == '=') {
217 named_labels = add_label(named_labels, end+1, address);
218 }
219 }
220 }
221 FILE * f = fopen(argv[1], "rb");
222 fseek(f, 0, SEEK_END);
223 filesize = ftell(f);
224 fseek(f, 0, SEEK_SET);
225
226 char int_key[MAX_INT_KEY_SIZE];
227 if (vos)
228 {
229 vos_program_module header;
230 vos_read_header(f, &header);
231 vos_read_alloc_module_map(f, &header);
232 address_off = header.user_boundary;
233 address_end = address_off + filesize - 0x1000;
234 def = defer(header.main_entry_link.code_address, def);
235 named_labels = add_label(named_labels, "main_entry_link", header.main_entry_link.code_address);
236 for (int i = 0; i < header.n_modules; i++)
237 {
238 if (!reset || header.module_map_entries[i].code_address != header.user_boundary)
239 {
240 def = defer(header.module_map_entries[i].code_address, def);
241 }
242 named_labels = add_label(named_labels, header.module_map_entries[i].name.str, header.module_map_entries[i].code_address);
243 }
244 fseek(f, 0x1000, SEEK_SET);
245 filebuf = malloc(filesize - 0x1000);
246 if (fread(filebuf, 2, (filesize - 0x1000)/2, f) != (filesize - 0x1000)/2)
247 {
248 fprintf(stderr, "Failure while reading file %s\n", argv[1]);
249 }
250 fclose(f);
251 for(cur = filebuf; cur - filebuf < ((filesize - 0x1000)/2); ++cur)
252 {
253 *cur = (*cur >> 8) | (*cur << 8);
254 }
255 if (reset)
256 {
257 def = defer(filebuf[2] << 16 | filebuf[3], def);
258 named_labels = add_label(named_labels, "reset", filebuf[2] << 16 | filebuf[3]);
259 }
260 } else {
261 address_end = address_off + filesize;
262 filebuf = malloc(filesize);
263 if (fread(filebuf, 2, filesize/2, f) != filesize/2)
264 {
265 fprintf(stderr, "Failure while reading file %s\n", argv[1]);
266 }
267 fclose(f);
268 for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
269 {
270 *cur = (*cur >> 8) | (*cur << 8);
271 }
272 uint32_t start = filebuf[2] << 16 | filebuf[3];
273 uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2];
274 uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2];
275 uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2];
276 named_labels = add_label(named_labels, "start", start);
277 named_labels = add_label(named_labels, "int_2", int_2);
278 named_labels = add_label(named_labels, "int_4", int_4);
279 named_labels = add_label(named_labels, "int_6", int_6);
280 if (!def || !only) {
281 def = defer(start, def);
282 def = defer(int_2, def);
283 def = defer(int_4, def);
284 def = defer(int_6, def);
285 }
286 }
287 uint16_t *encoded, *next;
288 uint32_t size, tmp_addr;
289 uint32_t address;
290 while(def) {
291 do {
292 encoded = NULL;
293 address = def->address;
294 if (!is_visited(address)) {
295 encoded = filebuf + (address - address_off)/2;
296 }
297 tmpd = def;
298 def = def->next;
299 free(tmpd);
300 } while(def && encoded == NULL);
301 if (!encoded) {
302 break;
303 }
304 for(;;) {
305 if (address > address_end || address < address_off) {
306 break;
307 }
308 visit(address);
309 next = m68k_decode(encoded, &instbuf, address);
310 address += (next-encoded)*2;
311 encoded = next;
312 //m68k_disasm(&instbuf, disbuf);
313 //printf("%X: %s\n", instbuf.address, disbuf);
314 check_reference(&instbuf, &(instbuf.src));
315 check_reference(&instbuf, &(instbuf.dst));
316 if (instbuf.op == M68K_ILLEGAL || instbuf.op == M68K_RTS || instbuf.op == M68K_RTE || instbuf.op == M68K_INVALID) {
317 break;
318 }
319 if (instbuf.op == M68K_BCC || instbuf.op == M68K_DBCC || instbuf.op == M68K_BSR) {
320 if (instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) {
321 address = instbuf.address + 2 + instbuf.src.params.immed;
322 encoded = filebuf + (address - address_off)/2;
323 reference(address);
324 if (is_visited(address)) {
325 break;
326 }
327 } else {
328 tmp_addr = instbuf.address + 2 + instbuf.src.params.immed;
329 reference(tmp_addr);
330 def = defer(tmp_addr, def);
331 }
332 } else if(instbuf.op == M68K_JMP) {
333 if (instbuf.src.addr_mode == MODE_ABSOLUTE || instbuf.src.addr_mode == MODE_ABSOLUTE_SHORT) {
334 address = instbuf.src.params.immed;
335 encoded = filebuf + (address - address_off)/2;
336 if (is_visited(address)) {
337 break;
338 }
339 } else if (instbuf.src.addr_mode == MODE_PC_DISPLACE) {
340 address = instbuf.src.params.regs.displacement + instbuf.address + 2;
341 encoded = filebuf + (address - address_off)/2;
342 if (is_visited(address)) {
343 break;
344 }
345 } else {
346 break;
347 }
348 } else if(instbuf.op == M68K_JSR) {
349 if (instbuf.src.addr_mode == MODE_ABSOLUTE || instbuf.src.addr_mode == MODE_ABSOLUTE_SHORT) {
350 def = defer(instbuf.src.params.immed, def);
351 } else if (instbuf.src.addr_mode == MODE_PC_DISPLACE) {
352 def = defer(instbuf.src.params.regs.displacement + instbuf.address + 2, def);
353 }
354 }
355 }
356 }
357 if (labels) {
358 for (address = 0; address < address_off; address++) {
359 if (is_label(address)) {
360 printf("ADR_%X equ $%X\n", address, address);
361 }
362 }
363 for (address = filesize; address < (16*1024*1024); address++) {
364 char key[MAX_INT_KEY_SIZE];
365 tern_int_key(address, key);
366 label_names *names = tern_find_ptr(named_labels, key);
367 if (names) {
368 for (int i = 0; i < names->num_labels; i++)
369 {
370 printf("%s equ $%X\n", names->labels[i], address);
371 }
372 } else if (is_label(address)) {
373 printf("ADR_%X equ $%X\n", address, address);
374 }
375 }
376 puts("");
377 }
378 for (address = address_off; address < address_end; address+=2) {
379 if (is_visited(address)) {
380 encoded = filebuf + (address-address_off)/2;
381 m68k_decode(encoded, &instbuf, address);
382 if (labels) {
383 m68k_disasm_labels(&instbuf, disbuf, label_fun, named_labels);
384 char keybuf[MAX_INT_KEY_SIZE];
385 label_names * names = tern_find_ptr(named_labels, tern_int_key(address, keybuf));
386 if (names)
387 {
388 for (int i = 0; i < names->num_labels; i++)
389 {
390 printf("%s:\n", names->labels[i]);
391 }
392 } else if (is_label(instbuf.address)) {
393 printf("ADR_%X:\n", instbuf.address);
394 }
395 if (addr) {
396 printf("\t%s\t;%X\n", disbuf, instbuf.address);
397 } else {
398 printf("\t%s\n", disbuf);
399 }
400 } else {
401 m68k_disasm(&instbuf, disbuf);
402 printf("%X: %s\n", instbuf.address, disbuf);
403 }
404 }
405 }
406 return 0;
407}