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}