changeset 308:f8344bc4fd61

dspanal: char2coff utility written, compiles
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 28 Oct 2019 05:20:50 +0000
parents 8e816bba2ff7
children 493f73198267
files .hgignore dspanal/Makefile dspanal/char2coff.c dspanal/charparse.c dspanal/coffout.c dspanal/coffout.h
diffstat 6 files changed, 474 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Oct 28 02:37:47 2019 +0000
+++ b/.hgignore	Mon Oct 28 05:20:50 2019 +0000
@@ -22,6 +22,7 @@
 ^compal/osmovoodoo
 
 ^dspanal/char2bin$
+^dspanal/char2coff$
 ^dspanal/patchanal$
 
 ^leo-obj/.*\.ctypes$
--- a/dspanal/Makefile	Mon Oct 28 02:37:47 2019 +0000
+++ b/dspanal/Makefile	Mon Oct 28 05:20:50 2019 +0000
@@ -1,14 +1,19 @@
 CC=	gcc
 CFLAGS=	-O2
-PROGS=	char2bin patchanal
+SIMPLE=	char2bin patchanal
+CMPLX=	char2coff
+PROGS=	${SIMPLE} ${CMPLX}
 
 all:	${PROGS}
 
-${PROGS}:
+${SIMPLE}:
 	${CC} ${CFLAGS} -o $@ $@.c
 
 char2bin:	char2bin.c
 patchanal:	patchanal.c
 
+char2coff:	char2coff.o charparse.o coffout.o
+	${CC} ${CFLAGS} -o $@ $^
+
 clean:
 	rm -f ${PROGS} *.o *errs *.out
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dspanal/char2coff.c	Mon Oct 28 05:20:50 2019 +0000
@@ -0,0 +1,93 @@
+/*
+ * This program will convert C char array files into COFF
+ * for disassembly analysis.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "coffout.h"
+
+extern unsigned read_char_file();
+
+static u_char binbuffer[300000];
+static unsigned array_size;
+static u_char *array_ptr, *array_end;
+
+#define	MAX_SECTIONS	256
+
+static struct coff_section sections[MAX_SECTIONS];
+static unsigned nsections;
+
+static void
+add_section(addr, size, data)
+	uint32_t addr, size;
+	u_char *data;
+{
+	struct coff_section *sec;
+
+	if (nsections >= MAX_SECTIONS) {
+		fprintf(stderr, "error: too many sections\n");
+		exit(1);
+	}
+	sec = sections + nsections;
+	sec->addr = addr;
+	sec->size = size;
+	sec->data = data;
+	sec->flags = 0x0020;
+	sec->mempage = 0x00;
+	nsections++;
+}
+
+static uint32_t
+get_longword()
+{
+	uint32_t datum;
+
+	if (array_ptr + 4 > array_end) {
+		fprintf(stderr, "error: parse spills past end of array\n");
+		exit(1);
+	}
+	datum = (array_ptr[3] << 24) | (array_ptr[2] << 16) |
+		(array_ptr[1] << 8) | array_ptr[0];
+	array_ptr += 4;
+	return datum;
+}
+
+main(argc, argv)
+	char **argv;
+{
+	uint32_t addr, size;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s char-array-file coff-output-file\n",
+			argv[0]);
+		exit(1);
+	}
+	array_size = read_char_file(argv[1], binbuffer, sizeof binbuffer);
+	array_ptr = binbuffer;
+	array_end = array_ptr + array_size;
+	if (get_longword() != 0) {
+		fprintf(stderr, "error: initial tag 0 is missing\n");
+		exit(1);
+	}
+	if (get_longword() != 3) {
+		fprintf(stderr, "error: initial vers 3 is missing\n");
+		exit(1);
+	}
+	for (;;) {
+		size = get_longword();
+		if (size > 0x10000) {
+			fprintf(stderr, "error: section size unreasonable\n");
+			exit(1);
+		}
+		addr = get_longword();
+		if (!size)
+			break;
+		add_section(addr, size, array_ptr);
+		array_ptr += size << 1;
+	}
+	emit_coff_output(argv[2], sections, nsections);
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dspanal/charparse.c	Mon Oct 28 05:20:50 2019 +0000
@@ -0,0 +1,297 @@
+/*
+ * This module reads C char array files; it will be linked into programs
+ * that do further processing.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+/* lexer tokens */
+#define	WORD		256
+#define	NUMBER		257
+#define	HEXBYTE		258
+
+/* limits */
+#define	MAXWORD		63
+#define	MAXDIGITS	5
+
+static char *parser_filename;
+static FILE *parser_readF;
+static int parser_lineno;
+static char parser_read_word[MAXWORD+1];
+static int parser_read_number;
+
+static void
+parse_error(msg)
+	char *msg;
+{
+	fprintf(stderr, "%s line %d: %s\n", parser_filename, parser_lineno,
+		msg);
+	exit(1);
+}
+
+static
+my_getchar()
+{
+	register int c;
+
+	c = getc(parser_readF);
+	if (c < 0)
+		return(c);
+	if (!isascii(c))
+		parse_error("non-ASCII character");
+	if (iscntrl(c) && c != '\n' && c != '\t')
+		parse_error("invalid control character");
+	return(c);
+}
+
+static void
+handle_trad_comment()
+{
+	register int c, flag;
+
+	for (flag = 0; ; ) {
+		c = my_getchar();
+		if (c < 0)
+			parse_error("/* comment ends in EOF");
+		if (c == '\n')
+			parser_lineno++;
+		if (c == '/' && flag)
+			return;
+		flag = (c == '*');
+	}
+}
+
+static void
+handle_line_comment()
+{
+	register int c;
+
+	for (;;) {
+		c = my_getchar();
+		if (c < 0)
+			parse_error("// comment ends in EOF");
+		if (c == '\n') {
+			parser_lineno++;
+			return;
+		}
+	}
+}
+
+static void
+handle_comment()
+{
+	int c;
+
+	c = my_getchar();
+	switch (c) {
+	case '*':
+		/* traditional C comment style */
+		handle_trad_comment();
+		return;
+	case '/':
+		/* new-fangled double slash comment style */
+		handle_line_comment();
+		return;
+	default:
+		parse_error("character after '/' is not '*' or '/'");
+		exit(1);
+	}
+}
+
+static void
+handle_num_token(first_digit)
+{
+	register int c, n;
+
+	parser_read_number = first_digit - '0';
+	for (n = 1; ; n++) {
+		c = my_getchar();
+		if (!isdigit(c))
+			break;
+		parser_read_number *= 10;
+		parser_read_number += c - '0';
+	}
+	if (c >= 0) {
+		if (isalpha(c) || c == '_')
+			parse_error(
+			"digits followed by letters: neither word nor number");
+		ungetc(c, parser_readF);
+	}
+	if (n > MAXDIGITS)
+		parse_error("number is too long (MAXDIGITS exceeded)");
+}
+
+static int
+decode_hex_digit(c)
+	register int c;
+{
+	if (isdigit(c))
+		return(c - '0');
+	else if (isupper(c))
+		return(c - 'A' + 10);
+	else
+		return(c - 'a' + 10);
+}
+
+static void
+handle_hex_token()
+{
+	register int c, n;
+
+	c = my_getchar();
+	if (c != 'x' && c != 'X')
+		parse_error("\'0\' not followed by \'x\'");
+	parser_read_number = 0;
+	for (n = 0; n < 2; n++) {
+		c = my_getchar();
+		if (!isxdigit(c))
+			parse_error("0x not followed by two hex digits");
+		parser_read_number <<= 4;
+		parser_read_number += decode_hex_digit(c);
+	}
+}
+
+static void
+handle_word_token(first_char)
+{
+	register int c;
+	register char *cp;
+	register int len;
+
+	cp = parser_read_word;
+	*cp++ = first_char;
+	for (len = 1; ; ) {
+		c = my_getchar();
+		if (!isalnum(c) && c != '_')
+			break;
+		if (len >= MAXWORD)
+			parse_error("text token is too long");
+		*cp++ = c;
+		len++;
+	}
+	*cp = '\0';
+	if (c < 0)
+		return;
+	ungetc(c, parser_readF);
+}
+
+static int
+get_token()
+{
+	register int c;
+
+loop:	c = my_getchar();
+	switch (c) {
+	case EOF:
+		return(0);
+	case ' ':
+	case '\t':
+		goto loop;
+	case '\n':
+		parser_lineno++;
+		goto loop;
+	case '/':
+		handle_comment();
+		goto loop;
+	case ',':
+	case ';':
+	case '=':
+	case '[':
+	case ']':
+	case '{':
+	case '}':
+		return(c);
+	case '0':
+		handle_hex_token();
+		return(HEXBYTE);
+	}
+	if (isdigit(c)) {
+		handle_num_token(c);
+		return(NUMBER);
+	}
+	if (isalpha(c) || c == '_') {
+		handle_word_token(c);
+		return(WORD);
+	}
+	fprintf(stderr, "%s line %d: bad character \'%c\'\n", parser_filename,
+		parser_lineno, c);
+	exit(1);
+}
+
+unsigned
+read_char_file(filename, outbuf, buflimit)
+	char *filename;
+	u_char *outbuf;
+	unsigned buflimit;
+{
+	register int t;
+	u_char *outptr;
+	unsigned bytecnt;
+
+	parser_filename = filename;
+	parser_readF = fopen(parser_filename, "r");
+	if (!parser_readF) {
+		perror(parser_filename);
+		exit(1);
+	}
+	parser_lineno = 1;
+	t = get_token();
+	if (t != WORD || strcmp(parser_read_word, "const"))
+		parse_error("expected \"const\" keyword");
+	t = get_token();
+	if (t != WORD || strcmp(parser_read_word, "unsigned"))
+		parse_error("expected \"unsigned\" keyword");
+	t = get_token();
+	if (t != WORD || strcmp(parser_read_word, "char"))
+		parse_error("expected \"char\" keyword");
+	t = get_token();
+	if (t != WORD)
+		parse_error("expected char array name");
+	t = get_token();
+	if (t != '[')
+		parse_error("expected \'[\'");
+	t = get_token();
+	if (t == NUMBER)
+		t = get_token();
+	if (t != ']')
+		parse_error("expected \']\'");
+	t = get_token();
+	if (t != '=')
+		parse_error("expected \'=\'");
+	t = get_token();
+	if (t != '{')
+		parse_error("expected \'{\'");
+	/* get first hex byte */
+	t = get_token();
+	if (t != HEXBYTE)
+		parse_error("expected first hex byte");
+	outptr = outbuf;
+	*outptr++ = parser_read_number;
+	bytecnt = 1;
+	for (;;) {
+		t = get_token();
+		if (t == '}')
+			break;
+		if (t != ',')
+			parse_error("expected comma between bytes");
+		t = get_token();
+		if (t == '}')
+			break;
+		if (t != HEXBYTE)
+			parse_error("expected next hex byte");
+		if (bytecnt >= buflimit)
+			parse_error("buffer limit exceeded");
+		*outptr++ = parser_read_number;
+		bytecnt++;
+	}
+	t = get_token();
+	if (t != ';')
+		parse_error("expected terminating \';\'");
+	fclose(parser_readF);
+	return bytecnt;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dspanal/coffout.c	Mon Oct 28 05:20:50 2019 +0000
@@ -0,0 +1,69 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "coffout.h"
+
+static FILE *outF;
+
+static void
+write16(val)
+	unsigned val;
+{
+	putc(val, outF);
+	putc(val >> 8, outF);
+}
+
+static void
+write32(val)
+	unsigned val;
+{
+	putc(val, outF);
+	putc(val >> 8, outF);
+	putc(val >> 16, outF);
+	putc(val >> 24, outF);
+}
+
+emit_coff_output(filename, sections, nsect)
+	char *filename;
+	struct coff_section *sections;
+	unsigned nsect;
+{
+	uint32_t dataptr;
+	unsigned n;
+	char section_name[32];
+
+	outF = fopen(filename, "w");
+	if (!outF) {
+		perror(filename);
+		exit(1);
+	}
+	write16(0x00C1);
+	write16(nsect);
+	write32(0);
+	write32(0);
+	write32(0);
+	write16(0);
+	write16(0x0117);
+	write16(0x0098);
+	dataptr = 0x22 + 0x28 * nsect;
+	for (n = 0; n < nsect; n++) {
+		sprintf(section_name, "chunk%03u", n);
+		fwrite(section_name, 1, 8, outF);
+		write32(sections[n].addr);
+		write32(sections[n].addr);
+		write32(sections[n].size);
+		write32(dataptr);
+		dataptr += sections[n].size << 1;
+		write32(0);
+		write32(0);
+		write32(0);
+		write16(sections[n].flags);
+		putc(0, outF);
+		putc(sections[n].mempage, outF);
+	}
+	for (n = 0; n < nsect; n++)
+		fwrite(sections[n].data, 2, sections[n].size, outF);
+	fclose(outF);
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dspanal/coffout.h	Mon Oct 28 05:20:50 2019 +0000
@@ -0,0 +1,7 @@
+struct coff_section {
+	uint32_t	addr;
+	uint32_t	size;
+	u_char		*data;
+	uint16_t	flags;
+	u_char		mempage;
+};