view lwdisasm/main.c @ 448:5cccf90bf838 3.0 tip

Fixed bug with complex external references generating invalid relocations in the object file
author lost@l-w.ca
date Fri, 05 Nov 2010 22:27:00 -0600
parents cba03436c720
children
line wrap: on
line source

/*
main.c

Copyright © 2010 William Astle

This file is part of LWTOOLS.

LWTOOLS is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>

#include <argp.h>
#include <stdio.h>
#include <stdlib.h>

#include <lw_alloc.h>
#include <lw_string.h>

#include "lwdisasm.h"

/* command line option handling */
const char *argp_program_version = "lwdisasmasm from " PACKAGE_STRING;
const char *argp_program_bug_address = PACKAGE_BUGREPORT;
char *program_name;

static struct argp_option options[] =
{
	{ "output",		'o',	"FILE",		0,						"Output to FILE"},
	{ "debug",		'd',	"LEVEL",	OPTION_ARG_OPTIONAL,	"Set debug mode"},
	{ "format",		'f',	"TYPE",		0,						"Select input format: decb, raw, obj, os9"},
	{ "decb",		'b',	0,			0,						"Read DECB .bin format input, equivalent of --format=decb"},
	{ "raw",		'r',	0,			0,						"Read raw binary format input, equivalent of --format=raw"},
	{ "obj",		0x100,	0,			0,						"Read proprietary object file format, equivalent of --format=obj" },
	{ "6809",		'9',	0,			0,						"Set disassembler to 6809 only mode" },
	{ "6309",		'3',	0,			0,						"Set disassembler to 6309 mode (default)" },
	{ "data",		0x101,	"RANGE",	0,						"Set an address range as data" },
	{ "code",		0x102,	"RANGE",	0,						"Set an address range as code" },
	{ "entry",		0x103,	"ADDR",		0,						"Start disassembling at ADDR" },
	{ "base",		0x104,	"ADDR",		0,						"Set the base address of a raw file" },
	{ 0 }
};


static error_t parse_opts(int key, char *arg, struct argp_state *state)
{
	disasmstate_t *as = state -> input;
	int rangelow, rangehigh;
	char *e;
	
	switch (key)
	{
	
	case 0x101: // data range
		rangelow = strtol(arg, &e, 0);
		if (*e != ':')
		{
			fprintf(stderr, "Invalid range: %s\n", arg);
			exit(1);
		}
		rangehigh = strtol(e + 1, NULL, 0);
		if (rangelow < 0 || rangehigh < 0 || rangehigh < rangelow)
		{
			fprintf(stderr, "Invalid range: %s\n", arg);
			exit(1);
		}
		// register the range as data
		register_range(as, rangelow, rangehigh, type_data);
		break;
		
	case 0x102: // code range
		rangelow = strtol(arg, &e, 0);
		if (*e != ':')
		{
			fprintf(stderr, "Invalid range: %s\n", arg);
			exit(1);
		}
		rangehigh = strtol(e + 1, NULL, 0);
		if (rangelow < 0 || rangehigh < 0 || rangehigh < rangelow)
		{
			fprintf(stderr, "Invalid range: %s\n", arg);
			exit(1);
		}
		// register the range as code
		register_range(as, rangelow, rangehigh, type_code);
		break;
	
	case 0x103: // entry
		as -> entry = strtol(arg, NULL, 0);
		break;
		
	case 0x104: // base
		as -> base = strtol(arg, NULL, 0);
		break;
		
	case 'o':
		if (as -> output_file)
			lw_free(as -> output_file);
		as -> output_file = lw_strdup(arg);
		break;

	case 'd':
		if (!arg)
			as -> debug_level = 50;
		else
			as -> debug_level = atoi(arg);
		break;

	case 'b':
		as -> input_type = INPUT_DECB;
		break;

	case 'r':
		as -> input_type = INPUT_RAW;
		break;

	case 0x100:
		as -> input_type = INPUT_OBJ;
		break;

	case 'f':
		if (!strcasecmp(arg, "decb"))
			as -> input_type = INPUT_DECB;
		else if (!strcasecmp(arg, "raw"))
			as -> input_type = INPUT_RAW;
		else if (!strcasecmp(arg, "obj"))
			as -> input_type = INPUT_OBJ;
		else if (!strcasecmp(arg, "os9"))
			as -> input_type = INPUT_OS9;
		else
		{
			fprintf(stderr, "Invalid input format: %s\n", arg);
			exit(1);
		}
		break;
		
	case '9':
		as -> target = TARGET_6809;
		break;

	case '3':
		as -> target = TARGET_6309;
		break;

	case ARGP_KEY_END:
		break;
	
	case ARGP_KEY_ARG:
		if (as -> input_file)
		{
			fprintf(stderr, "Only one input file allowed\n");
			exit(1);
		}
		as -> input_file = lw_strdup(arg);
		break;
		
	default:
		return ARGP_ERR_UNKNOWN;
	}
	return 0;
}

static struct argp argp =
{
	options,
	parse_opts,
	"<input file>",
	"LWDISASM, a HD6309 and MC6809 disassembler"
};

/*
main function; parse command line, set up disassembler state, and run the 
disassembler on the first file
*/

void do_disasm_raw(disasmstate_t *as);

int main(int argc, char **argv)
{
	disasmstate_t as = { 0 };
	FILE *fp;
	
	/* assembler state */
	program_name = argv[0];

	/* parse command line arguments */	
	argp_parse(&argp, argc, argv, 0, 0, &as);

	if (as.input_file == NULL)
	{
		fprintf(stderr, "No input files specified.\n");
		exit(1);
	}
	
	fp = fopen(as.input_file, "rb");
	if (!fp)
	{
		perror("Cannot open input file");
		exit(1);
	}

	fseek(fp, 0, SEEK_END);
	as.filelen = ftell(fp);
	rewind(fp);
	
	as.filedata = lw_alloc(as.filelen);
	0 == fread(as.filedata, as.filelen, 1, fp);

	fclose(fp);

	switch (as.target)
	{
	case TARGET_6309:
		as.page0 = page0_6309;
		as.page1 = page1_6309;
		as.page2 = page2_6309;
		break;
		
	case TARGET_6809:
		as.page0 = page0_6809;
		as.page1 = page1_6809;
		as.page2 = page2_6809;
		break;
		
	default:
		as.page0 = page0_6809;
		as.page1 = page1_6809;
		as.page2 = page2_6809;
		break;
		
	}

	switch (as.input_type)
	{
	case INPUT_RAW:
		do_disasm_raw(&as);
		break;
		
	default:
		fprintf(stderr, "Input type is not currently implemented\n");
		exit(1);
	}

	exit(0);
}