view leo-obj/tool/hints.c @ 221:9f2e0c34fe33

ftmdump (C1xx factory data reverse eng) tool written
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 17 Nov 2017 19:58:07 +0000
parents 81fc8da9a29c
children
line wrap: on
line source

/*
 * Parsing of the disassembly hints file
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include "intstruct.h"
#include "globals.h"

static char *filename_for_err;
static int lineno;
static struct internal_scnhdr *section;
static struct hint *lasthint;

static void
set_section(name)
	char *name;
{
	unsigned n;
	struct internal_scnhdr *sec = 0;

	for (n = 0; n < nsections; n++)
		if (!strcmp(sections[n].name, name)) {
			sec = sections + n;
			break;
		}
	if (!sec) {
		fprintf(stderr, "%s line %d: no section named \"%s\" in %s\n",
			filename_for_err, lineno, name, objfilename);
		exit(1);
	}
	if (sec->hints) {
		fprintf(stderr, "%s line %d: [%s] given more than once\n",
			filename_for_err, lineno, name);
		exit(1);
	}
	section = sec;
	lasthint = 0;
}

static void
set_mode(arg)
	char *arg;
{
	char *cp;

	if (!section) {
		fprintf(stderr,
			"%s line %d: error: mode line outside of section\n",
			filename_for_err, lineno);
		exit(1);
	}
	while (isspace(*arg))
		arg++;
	if (!*arg) {
		fprintf(stderr, "%s line %d: mode line: missing argument\n",
			filename_for_err, lineno);
		exit(1);
	}
	for (cp = arg; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (!strcmp(arg, "code"))
		section->disasm_mode = DISASM_MODE_CODE;
	else if (!strcmp(arg, "data"))
		section->disasm_mode = DISASM_MODE_DATA;
	else if (!strcmp(arg, "bss"))
		section->disasm_mode = DISASM_MODE_BSS;
	else {
		fprintf(stderr, "%s line %d: unknown mode \"%s\"\n",
			filename_for_err, lineno, arg);
		exit(1);
	}
}

static void
regular_hint(arg1, arg2)
	char *arg1, *arg2;
{
	struct hint *hint;
	char *cp, *np;

	if (!section) {
		fprintf(stderr,
			"%s line %d: error: hint line outside of section\n",
			filename_for_err, lineno);
		exit(1);
	}
	hint = malloc(sizeof(struct hint));
	if (!hint) {
		perror("malloc");
		exit(1);
	}
	hint->pos = strtoul(arg1, &cp, 16);
	if (*cp == '-') {
		cp++;
		hint->endpos = strtoul(cp, &cp, 16);
	} else
		hint->endpos = hint->pos;
	if (*cp) {
		fprintf(stderr, "%s line %d: invalid hint position syntax\n",
			filename_for_err, lineno);
		exit(1);
	}
	if (hint->endpos < hint->pos) {
		fprintf(stderr, "%s line %d: range going backward\n",
			filename_for_err, lineno);
		exit(1);
	}
	if (lasthint && hint->pos <= lasthint->endpos) {
		fprintf(stderr, "%s line %d: hint pos <= previous\n",
			filename_for_err, lineno);
		exit(1);
	}
	hint->type = 0;
	hint->linebrk = 0;
	hint->next = 0;
	for (cp = arg2; isspace(*cp); cp++)
		;
	if (!*cp) {
		fprintf(stderr, "%s line %d: no keyword after hint pos\n",
			filename_for_err, lineno);
		exit(1);
	}
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (!strcmp(np, "linebrk") || !strcmp(np, "linebreak")) {
		hint->linebrk = 1;
		while (isspace(*cp))
			cp++;
		if (!*cp || *cp == '#') {
			if (hint->endpos != hint->pos) {
				fprintf(stderr,
			"%s line %d: no range allowed for linebrk hints\n",
					filename_for_err, lineno);
				exit(1);
			}
			goto out;
		}
		for (np = cp; *cp && !isspace(*cp); cp++)
			;
		if (*cp)
			*cp++ = '\0';
	}
	if (!strcmp(np, "d8"))
		hint->type = HINT_D8;
	else if (!strcmp(np, "d16"))
		hint->type = HINT_D16;
	else if (!strcmp(np, "d32"))
		hint->type = HINT_D32;
	else if (!strcmp(np, "asciz"))
		hint->type = HINT_ASCIZ;
	else {
		fprintf(stderr, "%s line %d: unknown hint keyword \"%s\"\n",
			filename_for_err, lineno, np);
		exit(1);
	}
	/* enforce alignment and range restrictions */
	switch (hint->type) {
	case HINT_D16:
		if (hint->pos & 1 || hint->endpos & 1) {
			fprintf(stderr, "%s line %d: d16 hint misaligned\n",
				filename_for_err, lineno);
			exit(1);
		}
		break;
	case HINT_D32:
		if (hint->pos & 3 || hint->endpos & 3) {
			fprintf(stderr, "%s line %d: d32 hint misaligned\n",
				filename_for_err, lineno);
			exit(1);
		}
		break;
	case HINT_ASCIZ:
		if (hint->endpos != hint->pos) {
			fprintf(stderr,
			"%s line %d: no range allowed for asciz hints\n",
				filename_for_err, lineno);
			exit(1);
		}
		break;
	}
out:	if (lasthint)
		lasthint->next = hint;
	else
		section->hints = hint;
	lasthint = hint;
}

read_hints_file(filename)
	char *filename;
{
	FILE *f;
	char linebuf[128], *cp, *np;

	f = fopen(filename, "r");
	if (!f) {
		perror(filename);
		exit(1);
	}
	filename_for_err = filename;
	for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) {
		for (cp = linebuf; isspace(*cp); cp++)
			;
		if (!*cp || *cp == '#')
			continue;
		if (*cp == '[') {
			np = ++cp;
			cp = index(cp, ']');
			if (!cp) {
				fprintf(stderr,
					"%s line %d: invalid section syntax\n",
					filename, lineno);
				exit(1);
			}
			*cp = '\0';
			set_section(np);
			continue;
		}
		for (np = cp; *cp && !isspace(*cp); cp++)
			;
		if (*cp)
			*cp++ = '\0';
		if (!strcmp(np, "mode")) {
			set_mode(cp);
			continue;
		}
		regular_hint(np, cp);
	}
	fclose(f);
	return(0);
}